• 博客园logo
  • 会员
  • 周边
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
netcore_vue
博客园    首页    新随笔    联系   管理    订阅  订阅

在IdentityServer4生成的JWT中添加一个自定义的Claim,用于ABP框架中要用到的token信息

用过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,即companyid的值?

  注入:private readonly ICurrentUser _currentUser;
然后调用:
var getcompayid = _currentUser.FindClaimValue("companyid");

 

posted @ 2024-06-22 11:16  梦想代码-0431  阅读(144)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3