【问题标题】:Asp.Net Core 3 Identity - Custom Claims not present in JWT from browserAsp.Net Core 3 Identity - 来自浏览器的 JWT 中不存在自定义声明
【发布时间】:2020-02-09 00:32:18
【问题描述】:

Asp.Net Core 3.0
我正在使用ASP.NET Core web application with Angular and Authentication(个人用户帐户)模板(来自 Visual Studio 2019)。
我的目的是在生成的JWT 中添加一些自定义声明并在浏览器中使用它们。
为了做到这一点,我扩展了UserClaimsPrincipalFactory

public class MyCustomClaimsInjector : UserClaimsPrincipalFactory<ApplicationUser>
{
    public MyCustomClaimsFactory(UserManager<ApplicationUser> userManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, optionsAccessor)
    {
    }

    protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
    {
        var id = await base.GenerateClaimsAsync(user);
        id.AddClaim(new Claim("my_claim1", "AdditionalClaim1"));
        id.AddClaim(new Claim("my_claim2", "AdditionalClaim2"));
        return id;
    }
}

同样,我已经在Startup.cs注册了扩展名

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddDefaultIdentity<ApplicationUser>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddClaimsPrincipalFactory<MyCustomClaimsFactory>();


        services.AddIdentityServer()
            .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

        services.AddAuthentication()
            .AddIdentityServerJwt();
        services.AddControllersWithViews();
        services.AddRazorPages();
        // In production, the Angular files will be served from this directory
        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "ClientApp/dist";
        });
    }

在登录阶段,从 SPA 客户端开始,调试器通过 MyCustomClaimsFactory 并将声明添加到 GenerateClaimsAsync 方法中的 ClaimsIdentity 中。

但是,我觉得奇怪的是为什么在浏览器中收到的 JWT 不包含 MyCustomClaimsFactory 添加的声明。

我是否希望在浏览器中看到 JWT 中的自定义声明?

任何人都可以建议深入研究的方向...为什么 JWT 中没有声明?

解码的 JWT 是:

SPA 应用程序:

【问题讨论】:

    标签: c# authentication jwt asp.net-core-identity asp.net-core-3.0


    【解决方案1】:

    将分享我的结果。希望这对其他人有帮助。

    我已经实现了IProfileService 并在ConfigureServices 中传递了.AddProfileService&lt;ProfileService&gt;()实现。

    public class ProfileService : IProfileService
    {
        protected UserManager<ApplicationUser> _userManager;
    
        public ProfileService(UserManager<ApplicationUser> userManager)
        {
            _userManager = userManager;
        }
    
        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {         
            var user = await _userManager.GetUserAsync(context.Subject);
    
            var claims = new List<Claim>
            {
                new Claim("my_FirstName", "user_FirstName"),
                new Claim("my_LastName", "user_LastName")
            };
    
            context.IssuedClaims.AddRange(claims);
        }
    
        public async Task IsActiveAsync(IsActiveContext context)
        {            
            var user = await _userManager.GetUserAsync(context.Subject);
    
            context.IsActive = (user != null);
        }
    }
    

    Startup.cs 文件

    services.AddIdentityServer()
            .AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
            .AddProfileService<ProfileService>();
    

    这样,现在 JWT 包含我的自定义声明
    我不确定为什么 UserClaimsPrincipalFactory 的覆盖无法解决这个问题。
    将尝试更深入地研究这些领域。

    【讨论】:

    • 您是否继续调查为什么使用 UserClaimsPrincipalFactory 设置声明不起作用?我今天遇到了同样的问题。
    • 在 gitter asp 频道开始聊天,但没有发现有用的信息。文档太原始了,我考虑等几个月,希望小版本会添加更多细节。我计划更新答案,一旦发现真正的原因。
    【解决方案2】:

    所以今天我遇到了同样的问题。我以前没有使用过 IdentityServer,所以我不确定以下是否是正确的做法,但它肯定比创建自己的 IProfileService 实现更容易。

    默认配置文件服务调用

    context.AddRequestedClaims(principal.Claims);
    

    请求的声明是在您正在访问的 IdentityServer ApiResource 上定义的。这个 ApiResource 配置是通过调用来创建的

    services.AddAuthentication()
            .AddIdentityServerJwt();
    

    这会创建一个名为“{Environment.ApplicationName}API”的默认 ApiResource 配置。 此对象还包含一组声明类型,以在生成 JWT 时包含。

    我找不到任何关于这是否也可以在 appsettings.json 中设置的文档,但您可以在启动代码中访问它。

    TLDR;将您的启动代码更改为类似于以下内容:

    Startup.cs:

    public class Startup
    {
        public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;
        }
    
        public IConfiguration Configuration { get; }
        public IWebHostEnvironment Environment { get; }
    
        // ...
    
        public void ConfigureServices(IServiceCollection services)
        {
            // ...
    
            services.AddIdentityServer()
                .AddApiAuthorization<User, ApplicationDbContext>(options =>
                {
                    // The options.ApiResources collection is automatically populated
                    // by services.AddAuthentication().AddIdentityServerJwt();
                    var apiResource = options.ApiResources[$"{Environment.ApplicationName}API"];
                    // Example: add the user's roles to the token
                    apiResource.UserClaims.Add(JwtClaimTypes.Role);
                    // Example: add another custom claim type
                    apiResource.UserClaims.Add("CustomClaimName");
                });
    
            services.AddAuthentication()
                .AddIdentityServerJwt();
    
            // ...
        }
    }
    

    【讨论】:

    • 您能否举例说明您添加的一些不同的声明类型?抱歉,我不太明白 ApiResource 对象的位置?
    • 我在代码中添加了 cmets 和一个使用真实声明类型的示例,希望它可以更清晰。 ApiResource 是自动创建的“options.ApiResources”集合中的配置对象。您可以在文档中了解更多信息:docs.identityserver.io/en/latest/reference/api_resource.html
    • 看来我在哪里创建了默认的 ApiResource 配置是错误的;我更新了代码,希望现在信息应该是正确的。
    猜你喜欢
    • 2019-04-15
    • 2018-07-01
    • 1970-01-01
    • 2019-04-22
    • 1970-01-01
    • 1970-01-01
    • 2022-06-30
    • 2019-12-28
    • 2017-04-20
    相关资源
    最近更新 更多