用过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())};// 确保添加用户的角色Claimvar 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 servicevar 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())};// 确保添加用户的角色Claimvar 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");}} }
生成的实际效果