Asp.net core'da güncel kullanıcı nasıl edinilir


130

E-posta gibi bir kullanıcının bilgilerini almak için mevcut bir kullanıcıyı almak istiyorum. Ama bunu asp.net çekirdeğinde yapamam. Kafam çok karıştı Bu benim kodum.

HttpContextdenetleyicinin yapıcısında neredeyse null . Her işlemde bir kullanıcı almak iyi değildir. Kullanıcı hakkında bir kez bilgi almak ve onları ayarlamak istiyorum ViewData;

public DashboardController()
{
    var user = HttpContext.User.GetUserId();
}

5
MVC veya Web APi ile mi kullanıyorsunuz?
Tushar

Yanıtlar:


173
User.FindFirst(ClaimTypes.NameIdentifier).Value

Oluşturucu için DÜZENLE

Aşağıdaki kod çalışır:

public Controller(IHttpContextAccessor httpContextAccessor)
{
    var userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value 
}

RTM için düzenle

Kaydolmalısınız IHttpContextAccessor:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
    }

2
eylemlerde çalışır. ama denetleyicinin yapıcısında kullanmak istiyorum.
Mehran Hafizi

3
bunu sınıflarda kullanmak mümkün mü?
Mehran Hafizi

5
ClaimTypes.NameIdentifiergeçerli kullanıcı kimliğini ClaimTypes.Nameverir ve kullanıcı adını verir.
Nikolay Kostov

3
Kimse bana UserPrincipal.Current.Name ile ilgili sorunun ne olduğunu söyleyebilir mi?
tipura

2
@ademcaglin Bazı nedenlerden dolayı Kullanıcı nullbenim durumumda geri mi dönüyor ? .Net core 2.1 Web apiYine de kullanıyorum .
Sruthi Varghese

55

Basit bir şekilde çalışıyor ve kontrol ettim.

private readonly UserManager<IdentityUser> _userManager;
public CompetitionsController(UserManager<IdentityUser> userManager)
{
    _userManager = userManager;
}

var user = await _userManager.GetUserAsync(HttpContext.User);

o zaman bu değişkenlerin tüm özelliklerini yapabilirsiniz user.Email. Umarım bu birine yardımcı olur.

Düzenle :

Görünüşe göre basit bir şey, ancak ASP.NET Core'daki farklı kimlik doğrulama sistemlerinin biraz karmaşık nedenidir. Güncelliyorum çünkü bazı insanlar alıyor null.

JWT Kimlik Doğrulaması için (ASP.NET Core v3.0.0-preview7 üzerinde test edilmiştir):

var email = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;

var user = await _userManager.FindByEmailAsync(email);

1
asp.net Core 2.0'daki bir denetleyicinin içinde benim için harika çalışıyor
jmdon

2
_userManager nedir?
NullVoxPopuli

6
ASP.NET Core Identity'de, Kullanıcı Yöneticisi, Kullanıcı Oluşturmak için Bağımlılık Ekleme tarafından sağlanan bir hizmettir. Daha fazla bilgi için belgelere bakın :
Ahmad

2
Eşzamansız olmayan bir yöntemde bu nasıl başarılabilir?
T3.0

Benim için boş dönüyor. Neden?
Alberto Cláudio Mandlate

22

Asp.NET Core'da mevcut kullanıcıyı edinmenin başka bir yolu var - ve sanırım burada bir yerde gördüm, SO ^^

// Stores UserManager
private readonly UserManager<ApplicationUser> _manager; 

// Inject UserManager using dependency injection.
// Works only if you choose "Individual user accounts" during project creation.
public DemoController(UserManager<ApplicationUser> manager)  
{  
    _manager = manager;  
}

// You can also just take part after return and use it in async methods.
private async Task<ApplicationUser> GetCurrentUser()  
{  
    return await _manager.GetUserAsync(HttpContext.User);  
}  

// Generic demo method.
public async Task DemoMethod()  
{  
    var user = await GetCurrentUser(); 
    string userEmail = user.Email; // Here you gets user email 
    string userId = user.Id;
}  

Bu kod DemoController adlı denetleyiciye gider. İkisi de beklemeden çalışmaz (derlenmez);)


Bu, Kimlik kullanımını gerektirir
Fraze

1
ApplicationUser nedir?
Mike

ApplicationUser, genellikle IdentityUser'dan miras alınır, bu nedenle ek özelliklerle, vb. Genişletilebilir.
Corgalore

20

Yapıcı içinde HttpContext'in boş olduğuna oldukça şaşırdığımı söylemeliyim. Eminim performans nedenlerinden dolayıdır. IPrincipalAşağıda açıklandığı gibi kullanmanın yapıcıya enjekte edilmesini sağladığını doğruladınız . Esasen kabul edilen cevapla aynı şeyi yapıyor, ancak daha arayüzey bir şekilde.


Bu soruyu bulan ve genel "Mevcut kullanıcı nasıl edinilir ?" Sorusuna cevap arayan herkes için. Userdoğrudan adresinden erişebilirsiniz Controller.User. Ancak bunu yalnızca eylem yöntemlerinin içinde yapabilirsiniz (sanırım, çünkü denetleyiciler yalnızca HttpContexts ile ve performans nedenleriyle çalışmaz).

Bununla birlikte, kurucuda buna ihtiyacınız varsa (OP'nin yaptığı gibi) veya mevcut kullanıcıya ihtiyaç duyan başka enjekte edilebilir nesneler oluşturmanız gerekiyorsa, aşağıdaki daha iyi bir yaklaşımdır:

Kullanıcı almak için IPrincipal enjekte edin

İlk tanışma IPrincipalveIIdentity

public interface IPrincipal
{
    IIdentity Identity { get; }
    bool IsInRole(string role);
}

public interface IIdentity
{
    string AuthenticationType { get; }
    bool IsAuthenticated { get; }
    string Name { get; }
}

IPrincipalve IIdentitykullanıcı ve kullanıcı adını temsil eder. 'Müdür' tuhaf gelirse Wikipedia sizi rahatlatacaktır .

Önemli gerçekleştirmek için buna öyle olsun ister IHttpContextAccessor.HttpContext.User, ControllerBase.Useryoksa ControllerBase.HttpContext.Usersen mi bir olması sağlanır nesneyi almak ClaimsPrincipalhangi uygular nesneIPrincipal .

Şu Useranda ASP.NET'in kullandığı başka bir Kullanıcı türü yoktur (ancak bu, başka bir şeyin uygulayamayacağı anlamına gelmez IPrincipal).

Dolayısıyla, enjekte edilmesini istediğiniz 'mevcut kullanıcı adı'na bağımlı olan bir şeyiniz varsa, enjekte etmelisiniz IPrincipalve kesinlikle yapmamalısınız IHttpContextAccessor.

Önemli:IPrincipal Doğrudan kontrol cihazınıza veya işlem yönteminize enjekte etmek için zaman kaybetmeyin - bu anlamsızdır çünkü Userzaten orada sizin için mevcuttur.

İçinde startup.cs:

   // Inject IPrincipal
   services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);

Daha sonra, kullanıcıya ihtiyaç duyan DI nesnenizde, sadece IPrincipalmevcut kullanıcıyı almak için enjekte edersiniz.

Buradaki en önemli şey, eğer birim testleri yapıyorsanız, bir tane göndermenize HttpContextgerek yoktur IPrincipal , sadece olabileni temsil eden bir şeyle dalga geçmeniz gerekir ClaimsPrincipal.

% 100 emin olmadığım bir ekstra önemli şey. Eğer gerçek iddiaları erişmesi gerekiyorsa dan ClaimsPrincipalsen döküm gerekir IPrincipaliçin ClaimsPrincipal. Bu sorun değil, çünkü çalışma zamanında bu türden olduğunu% 100 biliyoruz (çünkü öyle HttpContext.User). Aslında bunu yapıcıda yapmaktan hoşlanıyorum çünkü herhangi IPrincipal birinin a olacağını zaten kesin olarak biliyorum ClaimsPrincipal.

Alay ediyorsanız, doğrudan bir tane oluşturunClaimsPrincipal ve ne gerekiyorsa ona iletin IPrincipal.

Tam olarak neden arayüz IClaimsPrincipalolmadığından emin değilim. Sanırım MS ClaimsPrincipal, bunun bir arabirimi garanti etmeyen özel bir 'koleksiyon' olduğuna karar verdi .


2
Bu, mevcut kullanıcıyı uygulamanızın herhangi bir yerine enjekte etmenize olanak tanır, harika cevap!
Machado

1
Bu çalışmıyor. Ben her zaman nullenjekte edilirim IPrincipal. Ayrıca geçici hizmeti …GetService<IHttpContextAccessor>()?.HttpContext.User…(ile ?) olarak eklemem gerekiyordu çünkü aksi takdirde çökebilirdi (GetService null döndürdü).
ygoe

services.AddTransient(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);HttpContext.User bir ClaimsPrincipal olduğu gibi yapabilirsiniz .
Jay Zelos

18

Şu andan itibaren (Nisan 2017) aşağıdaki işlevlerin işe yaradığı görülüyor:

public string LoggedInUser => User.Identity.Name;

En azından bir Controller


4
'System.Security.Principal.IIdentity' türünü örtük olarak 'string' olarak dönüştüremezsiniz.
Anthony Huang

3
string LoggedInUser = User.Identity.Name;
Alic W

5
=>Operatörün daha önce böyle kullanıldığını görmemiş biri olarak buna "İfade Gövdesi Tanımı" denir ve bu belgede açıklanır . Benim gibi gelecekteki insanların merak etmesi durumunda.
Nathan Clement

En üstteki yorumda da belirtildiği gibi ' dan' IIdentityye dönüşüm olmadığı göz önüne alındığında, kodunuz düzenlemeden önce derlenemez string. Düzenleme bunu düzeltti. Ben de sonucunuza nasıl vardığınızdan emin değilim (özellikle "editör" puanları sadece 2k itibarın altındaki kullanıcılara verildiğinden).
fuglede

9

Belki cevabı görmedim, ama ben böyle yapıyorum.

  1. .Net Core -> Özellikler -> launchSettings.json

Bu değerleri değiştirmeniz gerekiyor

"windowsAuthentication": true, // needs to be true
"anonymousAuthentication": false,  // needs to be false 

Startup.cs -> ConfigureServices (...)

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

MVC veya Web Api Denetleyicisi

private readonly IHttpContextAccessor _httpContextAccessor;
//constructor then
_httpContextAccessor = httpContextAccessor;

Denetleyici yöntemi:

string userName = _httpContextAccessor.HttpContext.User.Identity.Name;

Sonuç, kullanıcıAdı örn. = Etki alanı \ kullanıcı adı


4

Benim sorunum, oturum açmış Kullanıcıya cshtml dosyasında bir nesne olarak erişmekti. Kullanıcıyı ViewData'da istediğinizi düşünürsek, bu yaklaşım yardımcı olabilir:

Cshtml dosyasında

@using Microsoft.AspNetCore.Identity
@inject UserManager<ApplicationUser> UserManager

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>
    @UserManager.FindByNameAsync(UserManager.GetUserName(User)).Result.Email
    </title>
  </head>
  <body>

  </body>
</html>

Yüklenecek bir gezinme özelliğini nasıl edinebileceğiniz hakkında herhangi bir fikir (ApplicationUser sınıfımdaki bir şirket gezinme özelliğinin şirket adı). Gezinme özelliklerini dahil etmenin bir yolunu görmedim.
Hunter Nelson

1

Mevcut yanıtlara ek olarak, uygulama genelinde kullanılabilir ve kullanıcıyla ilgili verileri UserIDvb. Tutan bir sınıf örneğine sahip olabileceğinizi eklemek isterim .

Yeniden düzenleme için yararlı olabilir, ör. UserIDHer denetleyici eyleminde getirmek ve UserIDHizmet Katmanı ile ilgili her yöntemde fazladan bir parametre bildirmek istemezsiniz .

Bir araştırma yaptım ve işte benim yazım .

Sadece özellik DbContextekleyerek UserId(veya Sessionbu özelliğe sahip özel bir sınıf uygulayarak) elde ettiğiniz sınıfınızı genişletirsiniz .

Filtre düzeyinde, sınıf örneğinizi getirebilir ve UserIddeğeri ayarlayabilirsiniz .

Bundan sonra örneğinizi nereye enjekte ederseniz edin - gerekli verilere sahip olacaktır (ömür istek başına olmalıdır , bu nedenle AddScopedyöntemi kullanarak kaydettirirsiniz ).

Çalışma örneği:

public class AppInitializationFilter : IAsyncActionFilter
{
    private DBContextWithUserAuditing _dbContext;

    public AppInitializationFilter(
        DBContextWithUserAuditing dbContext
        )
    {
        _dbContext = dbContext;
    }

    public async Task OnActionExecutionAsync(
        ActionExecutingContext context,
        ActionExecutionDelegate next
        )
    {
        string userId = null;
        int? tenantId = null;

        var claimsIdentity = (ClaimsIdentity)context.HttpContext.User.Identity;

        var userIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
        if (userIdClaim != null)
        {
            userId = userIdClaim.Value;
        }

        var tenantIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == CustomClaims.TenantId);
        if (tenantIdClaim != null)
        {
            tenantId = !string.IsNullOrEmpty(tenantIdClaim.Value) ? int.Parse(tenantIdClaim.Value) : (int?)null;
        }

        _dbContext.UserId = userId;
        _dbContext.TenantId = tenantId;

        var resultContext = await next();
    }
}

Daha fazla bilgi için cevabıma bakın .


0

Almak IdentityUserda işe yarar . Bu mevcut bir kullanıcı nesnesidir ve tüm kullanıcı değerleri alınabilir.

private readonly UserManager<IdentityUser> _userManager;
public yourController(UserManager<IdentityUser> userManager)
{
    _userManager = userManager;
}

var user = await _userManager.GetUserAsync(HttpContext.User);

0

Scafolded Identity kullanıyorsanız ve Asp.net Core 2.2+ kullanıyorsanız, mevcut kullanıcıya aşağıdaki gibi bir görünümden erişebilirsiniz:

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

 @if (SignInManager.IsSignedIn(User))
    {
        <p>Hello @User.Identity.Name!</p>
    }
    else
    {
        <p>You're not signed in!</p>
    }

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-2.2&tabs=visual-studio


0

Bu eski bir soru ama benim durumum, davamın burada tartışılmadığını gösteriyor.

Simon_Weaver'ın ( https://stackoverflow.com/a/54411397/2903893 ) yanıtını en çok beğendim . IPrincipal ve IIdentity kullanılarak nasıl kullanıcı adı alınacağını ayrıntılı olarak açıklıyor. Bu cevap kesinlikle doğrudur ve bu yaklaşımı kullanmanızı tavsiye ederim. Ancak, hata ayıklama sırasında ASP.NET, hizmet ilkesini düzgün şekilde dolduramadığında sorunla karşılaştım . (veya başka bir deyişle, IPrincipal.Identity.Name null)

MVC çerçevesinin kullanıcı adını almanın onu bir yerden alması gerektiği açıktır. .NET dünyasında, ASP.NET veya ASP.NET Core, Open ID Connect ara yazılımını kullanıyor. Basit senaryoda, web uygulamaları bir web tarayıcısında bir kullanıcının kimliğini doğrular. Bu senaryoda, web uygulaması kullanıcının tarayıcısını Azure AD'de oturum açması için yönlendirir. Azure AD, kullanıcının tarayıcısı aracılığıyla bir güvenlik belirtecinde kullanıcıyla ilgili talepleri içeren bir oturum açma yanıtı döndürür. Uygulamanızın kodunda çalışmasını sağlamak için, web uygulaması temsilcilerinin oturum açma yetkisini sağlamanız gerekir. Web uygulamanızı Azure Hizmeti'ne dağıttığınızda, bu gereksinimleri karşılayan yaygın senaryo, web uygulamasını yapılandırmaktır: "Uygulama Hizmetleri" -> Uygulamanız -> "Kimlik Doğrulama / Yetkilendirme" blade -> "Uygulama Hizmeti Kimlik Doğrulaması" = "Açık"https://github.com/Huachao/azure-content/blob/master/articles/app-service-api/app-service-api-authentication.md ). İnanıyorum ki (bu benim eğitimli tahminimdir) bu sürecin başlığı altında sihirbazın bu web uygulamasının "ana" web yapılandırmasını aşağıdaki paragraflarda gösterdiğim ayarları ekleyerek ayarladığını düşünüyorum. Temel olarak, bu yaklaşımın ASP.NET Core'da çalışmamasının nedeni "ana" makine yapılandırmasının webconfig tarafından yok sayılmasıdır. (Bu% 100 emin değil, sadece sahip olduğum en iyi açıklamayı veriyorum). Bu nedenle, çalışmasını sağlamak için bunu uygulamanızda manuel olarak kurmanız gerekir.

İşte Azure AD'yi kullanmak için uygulamanızı birçok kez nasıl kuracağınızı açıklayan bir makale. https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/aspnetcore2-2

Adım 1: Örneği Azure AD kiracınıza kaydedin. (Açıktır, açıklama zamanımı harcamak istemiyorum).

Adım 2: appsettings.json dosyasında: ClientID değerini, 1. Adımda Uygulama Kayıt portalına kaydettiğiniz uygulamadaki Uygulama Kimliği ile değiştirin. TenantId değerini ortak ile değiştirin

Adım 3: Startup.cs dosyasını açın ve ConfigureServices yönteminde .AddAzureAD içeren satırdan sonra, uygulamanızın Azure AD v2.0 uç noktasıyla kullanıcıları oturum açmasını sağlayan, hem İş hem de Okul ve Microsoft Kişisel hesapları.

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    options.Authority = options.Authority + "/v2.0/";
    options.TokenValidationParameters.ValidateIssuer = false;
});

Özet : Konu başlangıcının açıklandığı bir hataya neden olabilecek olası bir sorun daha gösterdim. Bu sorunun nedeni, Azure AD (Açık Kimlik ara yazılımı) için eksik yapılandırmalardır. Bu sorunu çözmek için manuel olarak "Kimlik Doğrulama / Yetkilendirme" kurulumunu öneriyorum. Bunun nasıl kurulacağına ilişkin kısa bir genel bakış eklenmiştir.


0

Cevapların çoğu HttpContextbelgelerden en iyi şekilde nasıl başa çıkılacağını gösteriyor , ki bu benim de yaptığım şey.

Hata ayıklarken proje ayarlarınızı kontrol etmek isteyeceğinizi belirtmek istedim, varsayılan olan Enable Anonymous Authentication = true.


-1

Çözümümü aldım

var claim = HttpContext.User.CurrentUserID();

public static class XYZ
{
    public static int CurrentUserID(this ClaimsPrincipal claim)
    {
        var userID = claimsPrincipal.Claims.ToList().Find(r => r.Type == 
         "UserID").Value;
        return Convert.ToInt32(userID);
    }
    public static string CurrentUserRole(this ClaimsPrincipal claim)
    {
        var role = claimsPrincipal.Claims.ToList().Find(r => r.Type == 
        "Role").Value;
        return role;
    }
}

1
Bu kod soruyu yanıtlayabilirken, sorunu nasıl ve neden çözdüğüne ilişkin ek bağlam sağlamak , yanıtlayanın uzun vadeli değerini artıracaktır.
Alexander
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.