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();
}
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>();
}
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.
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);)
Es scheint, dass ab sofort (April 2017) die folgenden Arbeiten funktionieren:
public string LoggedInUser => User.Identity;
Mindestens während einer Controller
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:
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.
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>
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 .
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>
}
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);
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.
Vielleicht habe ich die Antwort nicht gesehen, aber so mache ich es.
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