如何在 asp.net 核心中获取当前用户
本文关键字:获取 用户 核心 asp net | 更新日期: 2024-09-12 13:49:31
我想获取当前用户,以便可以访问他们的电子邮件地址等字段。但我不能在核心 asp.net 做到这一点。这是我的代码:
HttpContext
在控制器的构造函数中几乎为空。在每个操作中获取用户是不好的。我想获取一次用户的信息并将其保存到ViewData
;
public DashboardController()
{
var user = HttpContext.User.GetUserId();
}
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();
}
简单的工作方法,我检查了。
private readonly UserManager<IdentityUser> _userManager;
public CompetitionsController(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
var user = await _userManager.GetUserAsync(HttpContext.User);
然后你可以像user.Email
这样的变量的所有属性。我希望这会帮助某人。
编辑:
这是一件看似简单的事情,但 ASP.NET 核心中不同类型的身份验证系统有点复杂。我更新,因为有些人正在null
.
对于 JWT 身份验证(在 ASP.NET Core v3.0.0-preview 7 上测试(:
var email = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;
var user = await _userManager.FindByEmailAsync(email);
不得不说我很惊讶HttpContext在构造函数中是空的。我敢肯定这是出于性能原因。已确认使用如下所述的IPrincipal
确实会将其注入构造函数中。它本质上与公认的答案相同,但以更界面的方式。
对于任何找到这个问题的人,正在寻找通用"如何获得当前用户?">的答案,您可以直接从Controller.User
访问User
。但是您只能在操作方法中执行此操作(我假设是因为控制器不仅使用 HttpContext 运行,而且出于性能原因(。
但是 - 如果您在构造函数中需要它(如 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
表示用户和用户名。如果"校长"听起来很奇怪,维基百科会安慰你。
重要的是要意识到,无论你是从IHttpContextAccessor.HttpContext.User
、ControllerBase.User
还是ControllerBase.HttpContext.User
获得它,你都会得到一个保证是实现IPrincipal
的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
的东西,而这些东西可以只是ClaimsPrincipal
。
还有一件更重要的事情,我不是100%确定。如果需要从ClaimsPrincipal
访问实际声明,则需要将IPrincipal
转换为ClaimsPrincipal
。这很好,因为我们 100% 知道它在运行时属于该类型(因为这就是HttpContext.User
(。我实际上喜欢在构造函数中执行此操作,因为我已经确定任何IPrincipal
都将是ClaimsPrincipal
。
如果你在做模拟,只需直接创建一个ClaimsPrincipal
并将其传递给任何需要IPrincipal
的东西。
确切地说,为什么没有IClaimsPrincipal
界面,我不确定。我假设 MS 认为 ClaimsPrincipal
只是一个专门的"集合",不需要接口。
有另一种方法让当前用户进入 Asp.NET 核心 - 我想我在这里的某个地方看到了它,在 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 将无法工作(不会编译( ;)
截至目前(2017 年 4 月(,似乎以下工作:
public string LoggedInUser => User.Identity.Name;
至少在Controller
内
也许我没有看到答案,但这就是我的做法。
- .Net Core --> Properties --> 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;
结果是用户名,例如 = 域''用户名
我知道这里有很多正确答案,关于所有这些答案,我介绍这个技巧:
在启动中.cs
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
然后在任何需要 HttpContext 的地方,你都可以使用:
var httpContext = new HttpContextAccessor().HttpContext;
希望对;)有所帮助
我的问题是将登录的用户作为 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>
除了现有的答案之外,我还想补充一点,您还可以在应用程序范围内提供一个类实例,其中包含与用户相关的数据,如UserID
等。
它对于重构可能很有用,例如,您不想在每个控制器操作中获取UserID
并在与服务层相关的每个方法中声明一个额外的UserID
参数。
我做过研究,这是我的帖子。
您只需通过添加属性来扩展从DbContext
派生的类UserId
或实现具有此属性的自定义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();
}
}
有关更多信息,请参阅我的答案。
这是一个老问题,但我的案例表明我的案例没有在这里讨论。
我最喜欢Simon_Weaver(https://stackoverflow.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 应用:"应用服务"->"你的应用"->"身份验证/授权"边栏选项卡>"应用服务身份验证"="开",依此类推 (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。将租户 ID 值替换为通用
第 3 步:打开 Startup.cs 文件并在 配置服务 方法中,在包含 .AddAzureAD 插入以下代码,使应用程序能够使用 Azure AD v2.0 终结点(即工作和学校(登录用户,Microsoft个人帐户。
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters.ValidateIssuer = false;
});
总结:我已经展示了另一个可能的问题,该问题可能会导致主题启动器解释的错误。此问题的原因是缺少 Azure AD(开放 ID 中间件(的配置。为了解决这个问题,我建议手动设置"身份验证/授权"。添加了有关如何设置的简短概述。
采取IdentityUser
也可以。这是一个当前用户对象,可以检索用户的所有值。
private readonly UserManager<IdentityUser> _userManager;
public yourController(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
var user = await _userManager.GetUserAsync(HttpContext.User);
如果您使用的是折叠标识并使用 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://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-2.2&tabs=visual-studio
大多数答案都显示了如何最好地处理文档中的HttpContext
,这也是我所采用的。
我确实想提一下,您需要在调试时检查项目设置,默认值为 Enable Anonymous Authentication = true
。
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;
在探索了许多解决方案之后,以下是 ASP.NET 核心 5 对我有用的解决方案。
var claims = new List<Claim>(){
new Claim("Id", _user.Id)
};
如上面的代码片段所示,添加自定义"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 });
}
我使用 @Ahmed 提供的答案作为身份
为了获取当前用户 ID,我使用以下方法
var currentuserid = userManager.GetUserId(User);
为了获取与AspNetUsers表中登录用户相关的其他字段,我使用以下字段
var userorg = context.Users.Where(l=>l.Id== currentuserid).FirstOrDefaultAsync().Result.OrganizationId;
嗨,如果你愿意,你可以像这里一样在声明上获得id
var userId = User.Claims.FirstOrDefault(x => x.Type == JwtRegisteredClaimNames.Sub).Value;
对于那些想要获取 ASP.NET C# Web 应用程序的当前用户 - 即使在 IIS 上运行时,我个人在尝试了数小时后验证了我的研究中提到的许多其他选项。
string userName = User.Identity.Name;
请确保 IIS 上的 Web 应用程序的身份验证包括 Windows 身份验证。另外,请确保您的程序.cs文件包含...
using Microsoft.AspNetCore.Authentication.Negotiate;
builder.Services.AddControllersWithViews();
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy;
});
我得到了我的解决方案
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;
}
}