如何在asp.net core中获取当前用户
Posted
技术标签:
【中文标题】如何在asp.net core中获取当前用户【英文标题】:How to get current user in asp.net core 【发布时间】:2016-08-07 02:00:32 【问题描述】:我想获取当前用户,以便访问他们的电子邮件地址等字段。 但我不能在 asp.net 核心中做到这一点。 这是我的代码:
HttpContext
在控制器的构造函数中几乎为空。
在每个操作中都获得一个用户是不好的。我想一次性获取用户信息,保存到ViewData
;
public DashboardController()
var user = HttpContext.User.GetUserId();
【问题讨论】:
与 MVC 或 Web APi 一起使用? 【参考方案1】:User.FindFirst(ClaimTypes.NameIdentifier).Value
编辑构造函数
以下代码有效:
public Controller(IHttpContextAccessor httpContextAccessor)
var userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value
为 RTM 编辑
你应该注册IHttpContextAccessor
:
public void ConfigureServices(IServiceCollection services)
services.AddHttpContextAccessor();
【讨论】:
它在动作中工作。但我想在控制器的构造函数中使用。 可以在课堂上使用它吗?ClaimTypes.NameIdentifier
给出当前用户 ID,ClaimTypes.Name
给出用户名。
谁能告诉我 UserPrincipal.Current.Name 出了什么问题?
@ademcaglin 出于某种原因,在我的情况下,用户返回null
?我使用.Net core 2.1 Web api
。【参考方案2】:
简单的方法,我检查了。
private readonly UserManager<IdentityUser> _userManager;
public CompetitionsController(UserManager<IdentityUser> userManager)
_userManager = userManager;
var user = await _userManager.GetUserAsync(HttpContext.User);
然后你可以像user.Email
这样的变量的所有属性。我希望这会对某人有所帮助。
编辑:
这是一个看似简单但有点复杂的原因,因为 ASP.NET Core 中存在不同类型的身份验证系统。我更新是因为有些人收到了null
。
对于 JWT 身份验证(在 ASP.NET Core v3.0.0-preview7 上测试):
var email = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;
var user = await _userManager.FindByEmailAsync(email);
【讨论】:
在 asp.net Core 2.0 的控制器中非常适合我 什么是_userManager? 在 ASP.NET Core Identity 中,用户管理器是依赖注入提供的用于创建用户的服务。请参阅docs 了解更多信息: 如何在非异步方法中实现? 对我来说返回 null。为什么?【参考方案3】:我不得不说我很惊讶 HttpContext 在构造函数中为空。我确定这是出于性能原因。已确认使用IPrincipal
如下所述确实将其注入到构造函数中。它基本上与接受的答案相同,但以更界面的方式。
对于任何发现此问题并寻找通用“如何获取当前用户?”的答案的人,您可以直接从Controller.User
访问User
。但是您只能在操作方法中执行此操作(我假设是因为控制器不仅仅使用 HttpContexts 运行并且出于性能原因)。
但是 - 如果您在构造函数中需要它(就像 OP 一样)或需要创建其他需要当前用户的可注入对象,那么以下是更好的方法:
注入IPrincipal获取用户
第一次见面IPrincipal
和IIdentity
public interface IPrincipal
IIdentity Identity get;
bool IsInRole(string role);
public interface IIdentity
string AuthenticationType get;
bool IsAuthenticated get;
string Name get;
IPrincipal
和IIdentity
代表用户和用户名。 Wikipedia will comfort you if 'Principal' sounds odd.
重要的是要认识到,无论您是从IHttpContextAccessor.HttpContext.User
、ControllerBase.User
还是ControllerBase.HttpContext.User
获得它,您都获得了一个保证是实现ClaimsPrincipal
的ClaimsPrincipal
对象@ 对象.
目前没有 ASP.NET 用于 User
的其他类型的用户,(但这并不是说其他无法实现 IPrincipal
)。
因此,如果您想要注入与“当前用户名”相关的东西,您应该注入 IPrincipal
而绝对不是 IHttpContextAccessor
。
重要提示:不要浪费时间将 IPrincipal
直接注入您的控制器或操作方法 - 这是没有意义的,因为您已经可以使用 User
。
在startup.cs
:
// Inject IPrincipal
services.AddHttpContextAccessor();
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
然后在需要用户的 DI 对象中注入 IPrincipal
以获取当前用户。
这里最重要的是,如果你在做单元测试,你不需要发送HttpContext
,而只需要模拟代表IPrincipal
which can just beClaimsPrincipal
的东西。
还有一件我不能 100% 确定的额外重要的事情。如果您需要访问来自ClaimsPrincipal
的实际声明,则需要将IPrincipal
转换为ClaimsPrincipal
。这很好,因为我们 100% 知道在运行时它是那种类型(因为这就是 HttpContext.User
是)。我实际上喜欢在构造函数中执行此操作,因为我已经确定任何IPrincipal
都将是ClaimsPrincipal
。
如果您正在模拟,只需 create a ClaimsPrincipal
directly 并将其传递给任何需要 IPrincipal
。
究竟为什么IClaimsPrincipal
没有接口我不确定。我假设 MS 认为 ClaimsPrincipal
只是一个专门的“集合”,不需要接口。
【讨论】:
这允许您在应用程序的任何位置注入当前用户,很好的答案! 这不起作用。对于注入的IPrincipal
,我总是得到null
。我还需要将临时服务添加为…GetService<IHttpContextAccessor>()?.HttpContext.User…
(使用?
),否则它会崩溃(GetService 返回 null)。
你可以做 services.AddTransient(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
因为 HttpContext.User 是一个 ClaimsPrincipal。【参考方案4】:
有另一种在 Asp.NET Core 中获取当前用户的方法 - 我想我在这里的某个地方看到了它,在 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;
该代码转到名为 DemoController 的控制器。没有两个 await 将无法工作(不会编译);)
【讨论】:
这需要使用Identity 什么是ApplicationUser? ApplicationUser 通常继承自 IdentityUser,因此可以使用其他属性等进行扩展。【参考方案5】:截至目前(2017 年 4 月),以下工作似乎有效:
public string LoggedInUser => User.Identity.Name;
至少在Controller
内
【讨论】:
您不能将类型“System.Security.Principal.IIdentity”隐式转换为“字符串”。 字符串 LoggedInUser = User.Identity.Name; 作为以前没有见过=>
运算符这样使用的人,它被称为“表达式体定义”,在this documentation 中有描述。以防将来像我这样的人想知道。
您的代码不可能在编辑之前编译,因为没有从IIdentity
到string
的转换,正如顶部评论中所述。编辑只是解决了这个问题。我也不确定您是如何得出结论的(特别是因为“编辑”积分仅提供给声誉低于 2k 的用户)。【参考方案6】:
也许我没有看到答案,但我就是这样做的。
-
.Net Core --> 属性 --> launchSettings.json
您需要更改这些值
"windowsAuthentication": true, // needs to be true
"anonymousAuthentication": false, // needs to be false
Startup.cs --> ConfigureServices(...)
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
MVC 或 Web Api 控制器
private readonly IHttpContextAccessor _httpContextAccessor;
//constructor then
_httpContextAccessor = httpContextAccessor;
控制器方法:
string userName = _httpContextAccessor.HttpContext.User.Identity.Name;
结果是用户名,例如= 域\用户名
【讨论】:
这也与托管有关。您需要在 IIs 中禁用匿名身份验证才能使其正常工作。【参考方案7】:我的问题是将登录的用户作为 cshtml 文件中的对象进行访问。考虑到您希望 ViewData 中的用户,这种方法可能会有所帮助:
在cshtml文件中
@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>
【讨论】:
知道如何加载导航属性(我的 ApplicationUser 类上的公司导航属性的公司名称)。没有找到包含导航属性的方法。【参考方案8】:除了现有的答案,我想补充一点,您还可以在应用程序范围内使用一个类实例,其中包含与用户相关的数据,例如 UserID
等。
它可能对重构有用 例如您不想在每个控制器操作中获取UserID
并在每个与服务层相关的方法中声明一个额外的UserID
参数。
我做了一项研究,这里是my post。
您只需通过添加UserId
属性扩展您从DbContext
派生的类(或实现具有此属性的自定义Session
类)。
在过滤器级别,您可以获取您的类实例并设置UserId
值。
之后,无论您在哪里注入您的实例 - 它都将拥有必要的数据(生命周期必须是每个请求,因此您使用AddScoped
方法注册它)。
工作示例:
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();
欲了解更多信息,请参阅my answer。
【讨论】:
【参考方案9】:我知道这里有很多正确答案,对于所有这些,我介绍了这个技巧:
在 StartUp.cs 中
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
然后在任何需要 HttpContext 的地方都可以使用:
var httpContext = new HttpContextAccessor().HttpContext;
希望对你有所帮助;)
【讨论】:
【参考方案10】:这是个老问题,但我的案例表明这里没有讨论我的案例。
我最喜欢 Simon_Weaver (https://***.com/a/54411397/2903893) 的回答。他详细解释了如何使用 IPrincipal 和 IIdentity 获取用户名。这个答案是绝对正确的,我建议使用这种方法。但是,在调试过程中,我遇到了 ASP.NET 无法正确填充服务原则的问题。 (或者换句话说,IPrincipal.Identity.Name 为空)
很明显,要获取用户名,MVC 框架应该从某个地方获取它。在 .NET 世界中,ASP.NET 或 ASP.NET Core 正在使用 Open ID Connect 中间件。 在简单的场景中,Web 应用程序在 Web 浏览器中对用户进行身份验证。在这种情况下,Web 应用程序会引导用户的浏览器将他们登录到 Azure AD。 Azure AD 通过用户的浏览器返回登录响应,其中包含安全令牌中关于用户的声明。 要使其在您的应用程序代码中工作,您需要提供您的 Web 应用程序委派登录的权限。 当您将 Web 应用程序部署到 Azure 服务时,满足此要求的常见方案是配置 Web 应用程序:“应用程序服务”-> YourApp ->“身份验证/授权”刀片->“应用程序服务身份验证”=“开启”等等上(https://github.com/Huachao/azure-content/blob/master/articles/app-service-api/app-service-api-authentication.md)。我相信(这是我有根据的猜测),在此过程的底层,向导通过添加我在以下段落中显示的相同设置来调整此 Web 应用程序的“父”Web 配置。 基本上,这种方法在 ASP.NET Core 中不起作用的问题是因为 webconfig 忽略了“父”机器配置。 (这不是 100% 肯定的,我只是给出我所拥有的最好的解释)。因此,要使其正常工作,您需要在您的应用程序中手动设置它。
这是一篇文章,介绍了如何通过多种方式设置您的应用以使用 Azure AD。 https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/aspnetcore2-2
第 1 步:向您的 Azure AD 租户注册示例。 (很明显,不想花时间解释)。
第 2 步:在 appsettings.json 文件中: 将 ClientID 值替换为您在步骤 1 中在应用程序注册门户中注册的应用程序的应用程序 ID。 将 TenantId 值替换为 common
第 3 步:打开 Startup.cs 文件并在 ConfigureServices 方法中,在包含 .AddAzureAD 的行之后插入以下代码,这使您的应用程序能够使用 Azure AD v2.0 端点登录用户,即两者都是 Work以及学校和 Microsoft 个人帐户。
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters.ValidateIssuer = false;
);
总结:我已经展示了另一个可能的问题,它可能导致主题启动器被解释的错误。此问题的原因是缺少 Azure AD(Open ID 中间件)的配置。为了解决这个问题,我建议手动设置“身份验证/授权”。添加了如何设置的简短概述。
【讨论】:
【参考方案11】:使用IdentityUser
也可以。这是一个当前用户对象,可以检索到用户的所有值。
private readonly UserManager<IdentityUser> _userManager;
public yourController(UserManager<IdentityUser> userManager)
_userManager = userManager;
var user = await _userManager.GetUserAsync(HttpContext.User);
【讨论】:
【参考方案12】:如果您使用支架式身份并使用 Asp.net Core 2.2+,您可以从如下视图访问当前用户:
@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
【讨论】:
【参考方案13】:大多数答案都显示了如何最好地处理文档中的HttpContext
,这也是我所采用的。
我确实想提一下,在调试时你会想要检查你的项目设置,默认是Enable Anonymous Authentication = true
。
【讨论】:
【参考方案14】:if (access token in header or query parameter)
// Set the claims like in the Account/Login action from the interactive login form
var claims = ...;
// Local helper method, is used in other places, too
var claimsIdentity = await SignInAsync(httpContext, claims, false);
// Set user for the current request
// This works in that it's in User.Identity, but the auth events won't fire
httpContext.User = new ClaimsPrincipal(claimsIdentity);
和
var userEmail = HttpContext.User.FindFirst(ClaimTypes.Email).Value;
【讨论】:
【参考方案15】:在探索了许多解决方案之后,这就是我使用 ASP.NET core 5 的方法。
var claims = new List<Claim>()
new Claim("Id", _user.Id)
;
如上面的 sn-p 所示,添加自定义“Id”类型并将其设置为用户 id,同时准备要包含在 Jwt 令牌生成中的声明列表。 然后只需使用该声明来访问用户(此方法通过其 Id 唯一标识用户)。
var userEmail = User.FindFirstValue("Id");
var user = await _userManager.FindByIdAsync(userEmail);
这里是完整的解决方案: ->令牌生成辅助方法
public async Task<string> CreateToken()
var signingCredentials = GetSigningCredentials();
var claims = await GetClaims();
var tokenOptions = GenerateTokenOptions(signingCredentials, claims);
return new JwtSecurityTokenHandler().WriteToken(tokenOptions);
private SigningCredentials GetSigningCredentials()
var key = Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("JWT_SECRET"));
var secret = new SymmetricSecurityKey(key);
return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256);
private async Task<List<Claim>> GetClaims()
var claims = new List<Claim>()
new Claim("Id", _user.Id)
;
return claims;
private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, List<Claim> claims)
var jwtSettings = _configuration.GetSection("JwtSettings");
var tokenOptions = new JwtSecurityToken(
issuer: jwtSettings.GetSection("ValidIssuer").Value,
audience: jwtSettings.GetSection("ValidAudience").Value,
expires: DateTime.Now.AddMinutes(Convert.ToDouble(jwtSettings.GetSection("ExpiresIn").Value)),
signingCredentials: signingCredentials,
claims: claims
);
return tokenOptions;
这是获取登录用户的代码:
[HttpGet("user")]
public async Task<ActionResult<User>> GetUser()
var userId = User.FindFirstValue("Id");
var user = await _userManager.FindByIdAsync(userId);
return Ok(new User = User );
【讨论】:
【参考方案16】:我使用@Ahmed 为身份提供的答案
为了获取当前的用户 id,我使用下面的
var currentuserid = userManager.GetUserId(User);
为了在 AspNetUsers 表中获取与登录用户相关的其他字段,我使用以下内容
var userorg = context.Users.Where(l=>l.Id== currentuserid).FirstOrDefaultAsync().Result.OrganizationId;
【讨论】:
【参考方案17】:您好,如果您愿意,可以在此处获取索赔 ID
var userId = User.Claims.FirstOrDefault(x => x.Type == JwtRegisteredClaimNames.Sub).Value;
【讨论】:
【参考方案18】:我找到了解决办法
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;
【讨论】:
虽然此代码可以回答问题,但提供有关 如何 和 为什么 解决问题的附加上下文将提高答案的长期价值。以上是关于如何在asp.net core中获取当前用户的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 ASP.NET Core RC2 MVC6 和 IIS7 获取当前 Windows 用户
ASP.Net Core 如何在 EF Core 和 Identity 中获取用户角色
如何在 ASP.NET Core 5 MVC (.NET 5) 中获取记录的用户数据?
如何在 Asp.net core mvc 的控制器中获取自己的用户