ASP.NET Core 3.0 中获取当前经过身份验证的用户名的方式是什么?
What is the way in ASP.NET Core 3.0 to get current authenticated User username?
我正在研究最新的 ASP.NET Core 3.0 Angular 模板。我需要知道的是我们如何在 ActionFilterAttribute
中获得经过身份验证的用户和用户名。
ClaimTypes.NameIdentifier
returns当前用户id,ClaimTypes.Name
returns用户名,为null。
这是我的代码:
其中 getUser
的 UserId
为 d15f997a-6f65-4eb2-aecb-8b525361ae50
我还在 Startup class 中注册了 IHttpContextAccessor,如下所示:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
//Database Setup
services.AddDbContext<HashooDBContext>(Configuration.GetConnectionString("DefaultConnection"));
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddControllersWithViews();
services.AddRazorPages();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
return ContainerSetup.InitializeWeb(Assembly.GetExecutingAssembly(), services);
}
Controller.cs:
[Authorize]
[ApiController]
[Route("api/[controller]/{companycode}")]
public class DashboardTransactionsController : ControllerBase
{
[CustomAuthorizationFilter("companycode")]
public string Get()
{
return "Welcome";
}
}
请告诉我我做错了什么?
您可以使用 IHttpContextAccessor
private readonly IHttpContextAccessor _httpContextAccessor;
public UserService(
IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
要获取用户名,您可以使用
_httpContextAccessor?.HttpContext?.User?.Identity?.Name;
或者
_httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
然后在您的 Startup.cs
中注册
public void ConfigureServices(IServiceCollection services)
{
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
试试这个代码:
string userId = context.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
这个问题是由于IdentityServer4
没有把JwtClaimTypes.Name
加到access_token上造成的。如果您从网络浏览器查看 access_token,您会发现它缺少 "name": "Tom",
节点。
要解决此问题,您可以实施自己的 ITokenService
,例如
public class CustomTokenService : DefaultTokenService
{
public CustomTokenService(IClaimsService claimsProvider
, IReferenceTokenStore referenceTokenStore
, ITokenCreationService creationService
, IHttpContextAccessor contextAccessor
, ISystemClock clock
, IKeyMaterialService keyMaterialService
, ILogger<DefaultTokenService> logger)
: base(claimsProvider, referenceTokenStore, creationService, contextAccessor, clock, keyMaterialService, logger)
{
}
public override async Task<Token> CreateAccessTokenAsync(TokenCreationRequest request)
{
Logger.LogTrace("Creating access token");
request.Validate();
var claims = new List<Claim>();
claims.AddRange(await ClaimsProvider.GetAccessTokenClaimsAsync(
request.Subject,
request.Resources,
request.ValidatedRequest));
if (request.ValidatedRequest.Client.IncludeJwtId)
{
claims.Add(new Claim(JwtClaimTypes.JwtId, CryptoRandom.CreateUniqueId(16)));
}
claims.Add(new Claim(JwtClaimTypes.Name, request.Subject.GetDisplayName()));
var issuer = Context.HttpContext.GetIdentityServerIssuerUri();
var token = new Token(OidcConstants.TokenTypes.AccessToken)
{
CreationTime = Clock.UtcNow.UtcDateTime,
Issuer = issuer,
Lifetime = request.ValidatedRequest.AccessTokenLifetime,
Claims = claims.Distinct(new ClaimComparer()).ToList(),
ClientId = request.ValidatedRequest.Client.ClientId,
AccessTokenType = request.ValidatedRequest.AccessTokenType
};
foreach (var api in request.Resources.ApiResources)
{
if (!string.IsNullOrWhiteSpace(api.Name))
{
token.Audiences.Add(api.Name);
}
}
return token;
}
}
然后在身份配置前注册CustomTokenService
public void ConfigureServices(IServiceCollection services)
{
services.TryAddTransient<ITokenService, CustomTokenService>();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
}
对于一种简单的方法,您可以尝试覆盖 DefaultClaimsService.GetStandardSubjectClaims
,例如
public class CustomClaimsService : DefaultClaimsService
{
public CustomClaimsService(IProfileService profile
, ILogger<DefaultClaimsService> logger) : base(profile, logger)
{
}
protected override IEnumerable<Claim> GetStandardSubjectClaims(ClaimsPrincipal subject)
{
var claims = base.GetStandardSubjectClaims(subject);
var newClaims = new List<Claim>(claims)
{
new Claim(JwtClaimTypes.Name, subject.Identity.Name)
};
return newClaims;
}
}
然后像
一样注册
public void ConfigureServices(IServiceCollection services)
{
services.TryAddTransient<IClaimsService, CustomClaimsService>();
//services.TryAddTransient<ITokenService, CustomTokenService>();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
}
我正在研究最新的 ASP.NET Core 3.0 Angular 模板。我需要知道的是我们如何在 ActionFilterAttribute
中获得经过身份验证的用户和用户名。
ClaimTypes.NameIdentifier
returns当前用户id,ClaimTypes.Name
returns用户名,为null。
这是我的代码:
其中 getUser
的 UserId
为 d15f997a-6f65-4eb2-aecb-8b525361ae50
我还在 Startup class 中注册了 IHttpContextAccessor,如下所示:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
//Database Setup
services.AddDbContext<HashooDBContext>(Configuration.GetConnectionString("DefaultConnection"));
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddControllersWithViews();
services.AddRazorPages();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
return ContainerSetup.InitializeWeb(Assembly.GetExecutingAssembly(), services);
}
Controller.cs:
[Authorize]
[ApiController]
[Route("api/[controller]/{companycode}")]
public class DashboardTransactionsController : ControllerBase
{
[CustomAuthorizationFilter("companycode")]
public string Get()
{
return "Welcome";
}
}
请告诉我我做错了什么?
您可以使用 IHttpContextAccessor
private readonly IHttpContextAccessor _httpContextAccessor;
public UserService(
IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
要获取用户名,您可以使用
_httpContextAccessor?.HttpContext?.User?.Identity?.Name;
或者
_httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
然后在您的 Startup.cs
中注册public void ConfigureServices(IServiceCollection services)
{
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
试试这个代码:
string userId = context.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
这个问题是由于IdentityServer4
没有把JwtClaimTypes.Name
加到access_token上造成的。如果您从网络浏览器查看 access_token,您会发现它缺少 "name": "Tom",
节点。
要解决此问题,您可以实施自己的 ITokenService
,例如
public class CustomTokenService : DefaultTokenService
{
public CustomTokenService(IClaimsService claimsProvider
, IReferenceTokenStore referenceTokenStore
, ITokenCreationService creationService
, IHttpContextAccessor contextAccessor
, ISystemClock clock
, IKeyMaterialService keyMaterialService
, ILogger<DefaultTokenService> logger)
: base(claimsProvider, referenceTokenStore, creationService, contextAccessor, clock, keyMaterialService, logger)
{
}
public override async Task<Token> CreateAccessTokenAsync(TokenCreationRequest request)
{
Logger.LogTrace("Creating access token");
request.Validate();
var claims = new List<Claim>();
claims.AddRange(await ClaimsProvider.GetAccessTokenClaimsAsync(
request.Subject,
request.Resources,
request.ValidatedRequest));
if (request.ValidatedRequest.Client.IncludeJwtId)
{
claims.Add(new Claim(JwtClaimTypes.JwtId, CryptoRandom.CreateUniqueId(16)));
}
claims.Add(new Claim(JwtClaimTypes.Name, request.Subject.GetDisplayName()));
var issuer = Context.HttpContext.GetIdentityServerIssuerUri();
var token = new Token(OidcConstants.TokenTypes.AccessToken)
{
CreationTime = Clock.UtcNow.UtcDateTime,
Issuer = issuer,
Lifetime = request.ValidatedRequest.AccessTokenLifetime,
Claims = claims.Distinct(new ClaimComparer()).ToList(),
ClientId = request.ValidatedRequest.Client.ClientId,
AccessTokenType = request.ValidatedRequest.AccessTokenType
};
foreach (var api in request.Resources.ApiResources)
{
if (!string.IsNullOrWhiteSpace(api.Name))
{
token.Audiences.Add(api.Name);
}
}
return token;
}
}
然后在身份配置前注册CustomTokenService
public void ConfigureServices(IServiceCollection services)
{
services.TryAddTransient<ITokenService, CustomTokenService>();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
}
对于一种简单的方法,您可以尝试覆盖 DefaultClaimsService.GetStandardSubjectClaims
,例如
public class CustomClaimsService : DefaultClaimsService
{
public CustomClaimsService(IProfileService profile
, ILogger<DefaultClaimsService> logger) : base(profile, logger)
{
}
protected override IEnumerable<Claim> GetStandardSubjectClaims(ClaimsPrincipal subject)
{
var claims = base.GetStandardSubjectClaims(subject);
var newClaims = new List<Claim>(claims)
{
new Claim(JwtClaimTypes.Name, subject.Identity.Name)
};
return newClaims;
}
}
然后像
一样注册 public void ConfigureServices(IServiceCollection services)
{
services.TryAddTransient<IClaimsService, CustomClaimsService>();
//services.TryAddTransient<ITokenService, CustomTokenService>();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
}