web-dev-qa-db-de.com

Wie bekomme ich einen aktuellen Benutzer in asp.net core

Ich möchte aktuelle Benutzer erhalten, um Informationen über Benutzer zu erhalten, wie z. B. E-Mail . Aber ich kann das nicht in asp.net core tun. Ich bin so verwirrt Dies ist mein Code. 

HttpContext ist in constructor des Controllers fast null. Es ist nicht gut, den Benutzer in jeder Aktion zu erhalten. Ich möchte einmal Informationen über den Benutzer erhalten und sie in ViewData setzen.

    public DashboardController()
    {
        var user = HttpContext.User.GetUserId();
   }
65
Mehran Hafizi
User.FindFirst(ClaimTypes.NameIdentifier).Value

EDIT für Konstruktor

Der folgende Code funktioniert:

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

Bearbeiten für RTM

Sie sollten IHttpContextAccessor registrieren:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    }
105
adem caglin

Das funktioniert einfach und ich habe nachgesehen.

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

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

dann können Sie alle Eigenschaften dieser Variablen wie user.Email. Ich hoffe das würde jemandem helfen.

30
Ahmad

Sie haben einen anderen Weg, um aktuelle Benutzer in Asp.NET Core zu bekommen - und ich glaube, ich habe es irgendwo hier auf SO ^^ gesehen 

// 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;
}  

Dieser Code geht an den Controller mit dem Namen DemoController. Funktioniert nicht ohne beides warten (kompiliert nicht);)

20
Hekkaryk

Es scheint, dass ab sofort (April 2017) die folgenden Arbeiten funktionieren:

public string LoggedInUser => User.Identity;

Mindestens während einer Controller

11
Grandizer

Ich muss sagen, ich war ziemlich überrascht, dass HttpContext im Konstruktor null ist. Ich bin sicher, es ist aus Gründen der Leistung. Habe bestätigt, dass die Verwendung von IPrincipal, wie unten beschrieben, es in den Konstruktor injiziert. Es macht im Wesentlichen dasselbe wie die akzeptierte Antwort, aber auf eine Interface-Art und Weise.


Für alle, die diese Frage auf der Suche nach einer Antwort auf die allgemeine Frage "Wie komme ich zum aktuellen Benutzer?" finden, können Sie direkt über Controller.User Auf User zugreifen. Sie können dies jedoch nur innerhalb von Aktionsmethoden tun (ich gehe davon aus, dass Controller nicht nur mit HttpContexts und aus Leistungsgründen ausgeführt werden).

Wenn Sie es jedoch im Konstruktor benötigen (wie es OP getan hat) oder andere injizierbare Objekte erstellen müssen, die den aktuellen Benutzer benötigen, ist der folgende Ansatz besser:

Injizieren Sie IPrincipal, um Benutzer zu erhalten

Treffen Sie zuerst IPrincipal und IIdentity

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

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

IPrincipal und IIdentity stehen für den Benutzer und den Benutzernamen. Wikipedia wird Sie trösten, wenn 'Principal' seltsam klingt .

Es ist wichtig zu wissen, ob Sie es von IHttpContextAccessor.HttpContext.User, ControllerBase.User Oder ControllerBase.HttpContext.User Erhalten, dass Sie ein Objekt erhalten, das garantiert a ist ClaimsPrincipal Objekt, das IPrincipal implementiert .

Derzeit gibt es keinen anderen Benutzertyp, den ASP.NET für User verwendet (dies bedeutet jedoch nicht, dass etwas anderes IPrincipal nicht implementieren konnte).

Wenn Sie also etwas haben, das eine Abhängigkeit von dem 'aktuellen Benutzernamen' hat, den Sie injizieren möchten, sollten Sie IPrincipal und definitiv nicht IHttpContextAccessor injizieren.

Wichtig: Verschwenden Sie keine Zeit damit, IPrincipal direkt in Ihren Controller oder Ihre Aktionsmethode zu injizieren - es ist sinnlos, da User steht Ihnen dort bereits zur Verfügung.

In startup.cs:

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

Dann fügen Sie in Ihrem DI-Objekt, das den Benutzer benötigt, einfach IPrincipal ein, um den aktuellen Benutzer abzurufen.

Das Wichtigste hierbei ist, dass Sie bei Unit-Tests kein HttpContext einsenden müssen, sondern nur etwas verspotten müssen, das IPrincipal darstellt Das kann einfachClaimsPrincipal sein.

Eine zusätzliche wichtige Sache, bei der ich nicht 100% sicher bin. Wenn Sie von ClaimsPrincipal aus auf die tatsächlichen Ansprüche zugreifen möchten, müssen Sie IPrincipal in ClaimsPrincipal umwandeln. Dies ist in Ordnung, da wir zu 100% wissen, dass es zur Laufzeit von diesem Typ ist (da dies HttpContext.User Ist). Ich mache das eigentlich gerne einfach im Konstruktor, da ich sicher weiß, dass jedes IPrincipal ein ClaimsPrincipal sein wird.

Wenn Sie verspotten, erstellen Sie einfach direkt ein ClaimsPrincipal und übergeben Sie es an alles, was IPrincipal benötigt.

Genau deshalb gibt es keine Schnittstelle für IClaimsPrincipal Ich bin nicht sicher. Ich nehme an, MS hat entschieden, dass ClaimsPrincipal nur eine spezialisierte 'Sammlung' ist, die keine Schnittstelle rechtfertigt.

6
Simon_Weaver

Mein Problem war es, auf den angemeldeten Benutzer als Objekt in der cshtml-Datei zuzugreifen. Wenn Sie den Benutzer in ViewData haben möchten, könnte dieser Ansatz hilfreich sein:

In der cshtml-Datei

@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>
3
MikeMajara

Zusätzlich zu den vorhandenen Antworten möchte ich hinzufügen, dass Sie auch eine Klasseninstanz für die gesamte App zur Verfügung haben können, die benutzerbezogene Daten wie UserID usw. enthält.

Es kann nützlich sein für Refactoring z. Sie möchten UserID nicht in jeder Controller-Aktion abrufen und in jeder Methode, die sich auf Service Layer bezieht, einen zusätzlichen UserID -Parameter deklarieren.

Ich habe Nachforschungen angestellt und hier ist mein Beitrag .

Sie erweitern einfach Ihre Klasse, die Sie von DbContext ableiten, indem Sie die Eigenschaft UserId hinzufügen (oder eine benutzerdefinierte Klasse Session implementieren, die diese Eigenschaft hat).

Auf Filterebene können Sie Ihre Klasseninstanz abrufen und den Wert UserId festlegen.

Danach, wo immer Sie Ihre Instanz injizieren - sie enthält die erforderlichen Daten (die Lebensdauer muss pro Anforderung betragen, sodass Sie sie mit der Methode AddScoped registrieren).

Arbeitsbeispiel:

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();
    }
}

Weitere Informationen finden Sie unter meine Antwort .

1
Alex Herman

Wenn Sie die Scafolded-Identität verwenden und Asp.net Core 2.2+ verwenden, können Sie aus einer Ansicht wie der folgenden auf den aktuellen Benutzer zugreifen:

@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
Andrew

Es würde auch funktionieren, IdentityUser zu nehmen. Dies ist ein aktuelles Benutzerobjekt, und alle Werte des Benutzers können abgerufen werden.

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

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

Dies ist eine alte Frage, aber mein Fall zeigt, dass mein Fall hier nicht erörtert wurde.

Am besten gefällt mir die Antwort von Simon_Weaver ( https://stackoverflow.com/a/54411397/290389 ). Er erklärt ausführlich, wie der Benutzername mit IPrincipal und IIdentity abgerufen wird. Diese Antwort ist absolut richtig und ich empfehle, diesen Ansatz zu verwenden. Beim Debuggen trat jedoch das Problem auf, dass ASP.NET das Dienstprinzip NICHT ordnungsgemäß auffüllen kann . (oder mit anderen Worten, IPrincipal.Identity.Name ist null)

Es liegt auf der Hand, dass das MVC-Framework irgendwo herkommen sollte, um einen Benutzernamen zu erhalten. In der .NET-Welt verwendet ASP.NET oder ASP.NET Core die Open ID Connect-Middleware. In dem einfachen Szenario authentifizieren Web-Apps einen Benutzer in einem Webbrowser. In diesem Szenario weist die Webanwendung den Browser des Benutzers an, sich bei Azure AD anzumelden. Azure AD gibt eine Anmeldeantwort über den Browser des Benutzers zurück, die Ansprüche über den Benutzer in einem Sicherheitstoken enthält. Damit dies im Code für Ihre Anwendung funktioniert, müssen Sie die Berechtigung angeben, bei der sich die Web-App-Delegierten anmelden. Wenn Sie Ihre Webanwendung für Azure Service bereitstellen, müssen Sie im Allgemeinen die Webanwendung konfigurieren: "App Services" -> YourApp -> Blade "Authentication/Authorization" -> "App Service Authenticatio" = "On" und so weiter am ( https://github.com/Huachao/Azure-content/blob/master/articles/app-service-api/app-service-api-authentication.md ). Ich glaube (das ist meine Vermutung), dass der Assistent unter der Haube dieses Prozesses die übergeordnete Webkonfiguration dieser Webanwendung anpasst, indem er dieselben Einstellungen hinzufügt, die ich in den folgenden Absätzen zeige. Grundsätzlich ist das Problem, warum dieser Ansatz in ASP.NET Core NICHT funktioniert, darauf zurückzuführen, dass die übergeordnete Computerkonfiguration von webconfig ignoriert wird. (das ist nicht 100% sicher, ich gebe nur die beste Erklärung, die ich habe). Damit dies funktioniert, müssen Sie dies manuell in Ihrer App einrichten.

In diesem Artikel wird erläutert, wie Sie Ihre App häufig für die Verwendung von Azure AD einrichten. https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/aspnetcore2-2

Schritt 1: Registrieren Sie das Beispiel bei Ihrem Azure AD-Mandanten. (Es ist offensichtlich, dass ich meine Zeit nicht mit Erklärungen verbringen möchte.).

Schritt 2: In der Datei appsettings.json: Ersetzen Sie den ClientID-Wert durch die Anwendungs-ID der Anwendung, die Sie in Schritt 1 im Anwendungsregistrierungsportal registriert haben. Ersetzen Sie den TenantId-Wert durch common

Schritt 3: Öffnen Sie die Datei "Startup.cs" und fügen Sie in der ConfigureServices-Methode nach der Zeile mit ".AddAzureAD" den folgenden Code ein, mit dem Ihre Anwendung Benutzer mit dem Azure AD 2.0-Endpunkt "Work and School" und "Azure AD 2.0" anmelden kann Microsoft Persönliche Konten.

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

Zusammenfassung : Ich habe ein weiteres mögliches Problem aufgezeigt, das zu einem Fehler führen könnte, der in der Erklärung des Themenstarters enthalten ist. Der Grund für dieses Problem sind fehlende Konfigurationen für Azure AD (Open ID-Middleware). Um dieses Problem zu lösen, schlage ich vor, "Authentifizierung/Autorisierung" manuell einzurichten. Die kurze Übersicht über die Einrichtung wird hinzugefügt.

0
Roman Oira-Oira

Vielleicht habe ich die Antwort nicht gesehen, aber so mache ich es.

  1. . Net Core -> Eigenschaften -> launchSettings.json

Sie müssen diese Werte ändern

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

Startup.cs -> ConfigureServices (...)

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

MVC oder Web Api Controller

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

Controller-Methode:

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

Ergebnis ist Benutzername, z. = Domain\Benutzername

0
Tom Stickel