用过IdentityServer4或者熟悉ASP.NET Core认证的都应该知道有Claim,如何理解ids4中的Claim?
这里可以理解为声明
,我们每个用户都有多个Claim,每个Claim声明了用户的某个信息比如:Role=Admin,UserID=1000等等,这里Role,UserID每个都是用户的Claim,都是表示用户信息的单元
,我们不妨把它称为用户信息单元
。
Claim相关的解析 http://www.cnblogs.com/savorboard/p/aspnetcore-identity.html
需求:在ids4中加一个登录用户所属的公司ID(companyid),默认生成的token信息中的用户信息单元,一般包含如下信息:用户名、邮箱地址、电话号、角色信息等基本的用户单元信息
public virtual async Task CreateStandardResourcesAsync() { var resources = new[] { new IdentityServer4.Models.IdentityResources.OpenId(), new IdentityServer4.Models.IdentityResources.Profile(), new IdentityServer4.Models.IdentityResources.Email(), new IdentityServer4.Models.IdentityResources.Address(), new IdentityServer4.Models.IdentityResources.Phone(), new IdentityServer4.Models.IdentityResource("role", "Roles of the user", new[] {"role"}) }; foreach (var resource in resources) { foreach (var claimType in resource.UserClaims) { await AddClaimTypeIfNotExistsAsync(claimType); } await AddIdentityResourceIfNotExistsAsync(resource); } }
解析生成的token
如何在解析的token中加入一个自定义的claim?比如添加一个公司ID,有两种实现方式:
方法一
1. **创建自定义声明(Claim)**:
首先,需要在用户登录的时候,将`company`信息添加到用户的声明中。你可以在你的用户存储(例如,数据库)中存储`company`信息,并在用户登录时将其添加到用户的声明中。
2. **扩展ProfileService**:
你需要创建一个自定义的`ProfileService`,以便在生成JWT时包含自定义的声明。
public class UserProfileService : IProfileService { protected IdentityUserManager UserManager { get; } public UserProfileService(IdentityUserManager userManager) { UserManager = userManager; } public async Task GetProfileDataAsync(ProfileDataRequestContext context) { var user = await UserManager.GetUserAsync(context.Subject); if (user != null) { var claims = new List<Claim> { new Claim("companyid", "11111"), new Claim("name",user.Name), new Claim("user_name",user.UserName), new Claim("email",user.Email), new Claim("email_verified",user.EmailConfirmed.ToString()), new Claim("phone_number",user.PhoneNumber), new Claim("phone_number_verified",user.PhoneNumberConfirmed.ToString()) }; // 确保添加用户的角色Claim var roles = await UserManager.GetRolesAsync(user); foreach (var role in roles) { claims.Add(new Claim("role", role)); } context.IssuedClaims.AddRange(claims); } } public async Task IsActiveAsync(IsActiveContext context) { var user = await UserManager.GetUserAsync(context.Subject); context.IsActive = user != null; } }
3. **配置IdentityServer4**:
将自定义的`ProfileService`注册到IdentityServer4中。
public class Startup { public void ConfigureServices(IServiceCollection services) { // 其他服务配置... // 注册自定义的Profile服务 services.AddTransient<IProfileService, UserProfileService>(); // IdentityServer的其他配置... } }
方法二
参照APB官网给的示例,来实现,推荐方法
参见地址: https://docs.abp.io/en/abp/latest/Authorization#claims-principal-factory
public class SocialSecurityNumberClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency { public async Task ContributeAsync(AbpClaimsPrincipalContributorContext context) { var identity = context.ClaimsPrincipal.Identities.FirstOrDefault(); var userId = identity?.FindUserId(); if (userId.HasValue) { var userService = context.ServiceProvider.GetRequiredService<IUserService>(); //Your custom service var socialSecurityNumber = await userService.GetSocialSecurityNumberAsync(userId.Value); if (socialSecurityNumber != null) { identity.AddClaim(new Claim("SocialSecurityNumber", socialSecurityNumber)); } } } } Configure<AbpClaimsServiceOptions>(options=> { options.RequestedClaims.Add("SocialSecurityNumber") }) public static class CurrentUserExtensions { public static string GetSocialSecurityNumber(this ICurrentUser currentUser) { return currentUser.FindClaimValue("SocialSecurityNumber"); } }
模拟方法如下:
using AuthServer.Host.Dappers; using IdentityServer4.Extensions; using IdentityServer4.Models; using IdentityServer4.Services; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Security.Principal; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Identity; using Volo.Abp.Security.Claims; using Volo.Abp.Users; using static Volo.Abp.Identity.Settings.IdentitySettingNames; namespace AuthServer.Host { public class Config { public static IEnumerable<IdentityServer4.Models.IdentityResource> GetIdentityResourceResources() { var customProfile = new IdentityServer4.Models.IdentityResource( name: "custom.profile", displayName: "Custom profile", userClaims: new[] { "companyid" }); return new List<IdentityServer4.Models.IdentityResource> { new IdentityResources.OpenId(), new IdentityResources.Profile(), customProfile }; } } public class UserProfileService : IProfileService { protected IdentityUserManager UserManager { get; } public UserProfileService(IdentityUserManager userManager) { UserManager = userManager; } public async Task GetProfileDataAsync(ProfileDataRequestContext context) { var user = await UserManager.GetUserAsync(context.Subject); if (user != null) { var claims = new List<Claim> { new Claim("companyid", "11111"), new Claim("name",user.Name), new Claim("user_name",user.UserName), new Claim("email",user.Email), new Claim("email_verified",user.EmailConfirmed.ToString()), new Claim("phone_number",user.PhoneNumber), new Claim("phone_number_verified",user.PhoneNumberConfirmed.ToString()) }; // 确保添加用户的角色Claim var roles = await UserManager.GetRolesAsync(user); foreach (var role in roles) { claims.Add(new Claim("role", role)); } context.IssuedClaims.AddRange(claims); } } public async Task IsActiveAsync(IsActiveContext context) { var user = await UserManager.GetUserAsync(context.Subject); context.IsActive = user != null; } } public class SocialSecurityNumberClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency { private readonly DapperDbContext _dbDapperContext; protected IdentityUserManager UserManager { get; } public SocialSecurityNumberClaimsPrincipalContributor(DapperDbContext dbDapperContext, IdentityUserManager userManager) { _dbDapperContext = dbDapperContext; UserManager = userManager; } public async Task ContributeAsync(AbpClaimsPrincipalContributorContext context) { var identity = context.ClaimsPrincipal.Identities.FirstOrDefault(); var userId = identity?.FindUserId(); if (userId.HasValue) { var user = await UserManager.GetUserAsync(context.ClaimsPrincipal); identity.AddClaim(new Claim("username", user.Name));//登录用户名 string sql = @$"SELECT OrganizationId FROM [dbo].[base_user_orgs] WHERE UserId=('{userId}') "; var org=await _dbDapperContext.QueryAsync<Guid>(sql, databaseType: DatabaseType.Default); var companyId = org.Any() ? string.Join(",",org.ToList()) : "";//会有同一个属于多个公司 identity.AddClaim(new Claim("companyid", companyId));//测试用 //var userService = context.ServiceProvider.GetRequiredService<IUserService>(); //Your custom service //var socialSecurityNumber = await userService.GetSocialSecurityNumberAsync(userId.Value); //if (socialSecurityNumber != null) //{ // identity.AddClaim(new Claim("SocialSecurityNumber", socialSecurityNumber)); //} } } } public static class CurrentUserExtensions { public static string GetSocialSecurityNumber(this ICurrentUser currentUser) { return currentUser.FindClaimValue("companyid"); } } }
生成的实际效果
标签:Claim,中要,自定义,user,context,var,new,public From: https://www.cnblogs.com/netcore-vue/p/18262020