.net-core - 在客户端向 Principal 添加自定义声明(用于授权)
问题描述
我已经能够在 .net core 3.1 上成功实现我自己的 IdentityServer4 身份验证服务器,并且我有一个客户端 Web 应用程序连接到它。客户端成功接收访问令牌和 ID。令牌包含所有用户识别信息。
我的下一个目标是在我获得令牌之后,在呈现任何其他页面之前,将用户在客户端中拥有的权限作为声明添加到 HttpContext.User。权限存储在通过 subjectId 与用户关联的数据库中。
我需要有关在哪里可以添加这些声明的帮助,以便我的授权策略可以与主体中的声明一起使用。我希望每次发行令牌时都执行该过程。
PS我正在使用GetClaimsFromUserInfoEndpoint = true和SaveTokens = true的身份服务器的代码流。
谢谢!
解决方案
您可以在 identityServer4 中使用 Profile sevise:
services .AddIdentityServer(x =>
{
x.IssuerUri = "null";
x.Authentication.CookieLifetime = TimeSpan.FromDays(10);
})
.
.
.
.AddProfileService<ProfileService>();
这是一个很好的参考:http ://docs.identityserver.io/en/latest/reference/profileservice.html 而 ProfileService 可以是这样的代码模板:
public class ProfileService : IProfileService
{
private readonly UserManager<ApplicationUser> _userManager;
public ProfileService(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var subject = context.Subject ?? throw new ArgumentNullException(nameof(context.Subject));
var subjectId = subject.Claims.Where(x => x.Type == "sub").FirstOrDefault().Value;
var user = await _userManager.FindByIdAsync(subjectId);
if (user == null)
throw new ArgumentException("Invalid subject identifier");
var claims = GetClaimsFromUser(user,subject);
context.IssuedClaims = claims.Result.ToList();
}
public async Task IsActiveAsync(IsActiveContext context)
{
var subject = context.Subject ?? throw new ArgumentNullException(nameof(context.Subject));
var subjectId = subject.Claims.Where(x => x.Type == "sub").FirstOrDefault().Value;
var user = await _userManager.FindByIdAsync(subjectId);
context.IsActive = false;
if (user != null)
{
if (_userManager.SupportsUserSecurityStamp)
{
var security_stamp = subject.Claims.Where(c => c.Type == "security_stamp").Select(c => c.Value).SingleOrDefault();
if (security_stamp != null)
{
var db_security_stamp = await _userManager.GetSecurityStampAsync(user);
if (db_security_stamp != security_stamp)
return;
}
}
context.IsActive =
!user.LockoutEnabled ||
!user.LockoutEnd.HasValue ||
user.LockoutEnd <= DateTime.Now;
}
}
private async Task<IEnumerable<Claim>> GetClaimsFromUser(ApplicationUser user,ClaimsPrincipal subject)
{
var claims = new List<Claim>
{
new Claim(JwtClaimTypes.Subject, user.Id),
new Claim(JwtClaimTypes.PreferredUserName, user.UserName),
new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)
};
if (!string.IsNullOrWhiteSpace(user.Name))
claims.Add(new Claim("name", user.Name));
if (!string.IsNullOrWhiteSpace(user.LastName))
claims.Add(new Claim("last_name", user.LastName));
return claims;
}
}
推荐阅读
- windows - 从绑定重定向中排除本地主机
- verilog - 在always块内生成语句,有可能吗?
- laravel - 如何使用 laravel 到 vue 组件的路由从 url 解析 slug
- forms - 使用 Drupal 8 验证多个电子邮件地址
- reactjs - react-router-dom url 更改但没有视图更新(withRouter 无限刷新)
- javascript - 没有在表单 Drupal 7 上添加 JS
- c# - 从 IQueryable 获取最后一个元素的扩展方法
- javascript - 无法读取未定义的属性“fromProject” – 怎么了?
- node.js - 如何在nodejs中存储shell命令的输出并将其用于其他操作
- tsql - 创建过滤索引时出现语法错误