【问题标题】:How to pass created user claims to client如何将创建的用户声明传递给客户端
【发布时间】:2020-04-21 00:57:54
【问题描述】:

我创建了多个声明,这些声明位于 AspNetUserClaims 表中以获取身份,并将它们分配给我的用户 ID。

我目前正在尝试将这些内容纳入我在客户端应用程序中收到的声明列表中。

通过将“角色”范围添加到我的客户端身份设置,然后还在身份配置中(使用 EF 数据库格式又名 ConfigurationDbContext)在IdentityResources 表链接到称为“角色”的身份声明。

这按预期工作。但是,我没有通过我创建的任何 UserClaims 获得,我需要创建另一个特定范围吗?

这是我的客户端配置:

services.AddAuthentication(options =>
    {
        options.DefaultScheme = "cookie";
        options.DefaultChallengeScheme = "oidc";
    })
    .AddCookie("cookie")
    .AddOpenIdConnect("oidc", options =>
    {
        options.Authority = "https://localhost:44335/";
        options.ClientId = "openIdConnectClient";
        options.SignInScheme = "cookie";
        options.ResponseType = "id_token";
        options.GetClaimsFromUserInfoEndpoint = true;
        options.Scope.Add("openid profile roles all_claims");
    });

services.AddAuthorization();

这就是我检查用户声明的方式:

var claims = ((ClaimsIdentity)User.Identity).Claims;

它返回所有角色和配置文件声明(例如,preferred_username),而不是在 AspNetUserClaims 表中指定的那些。

对于我的客户,我还将属性 [AlwaysIncludeUserClaimsInIdToken] 设置为 true,但没有成功。

有人知道我在通过用户声明时缺少什么吗?

【问题讨论】:

    标签: c# asp.net-identity identityserver4


    【解决方案1】:

    您可以像这样获得用户声明:

    var claims = User.Claims.Select(c => new { c.Type, c.Value });
    

    您可以在您的 api 中将其实现为端点,您在身份服务器中将其声明为范围:

    using IdentityServer4;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using System.Linq;
    
    namespace IdentityServer4Demo.Api
    {
        [Route("/api/test")]
        [Authorize]
        public class TestController : ControllerBase
        {
            public IActionResult Get()
            {
                var claims = User.Claims.Select(c => new { c.Type, c.Value });
                return new JsonResult(claims);
            }
        }
    }
    

    如果您想添加更多声明,您需要向实现 IdentityUser 的类添加属性并在您的自定义配置文件服务中使用它

    using Microsoft.AspNetCore.Identity;
    
    namespace AuthServer.Infrastructure.Data.Identity
    {
        public class AppUser : IdentityUser
        {
            // Add additional profile data for application users by adding properties to this class
            public string Name { get; set; }        
        }
    }
    

    您的自定义配置文件服务:

    using System.Linq;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using AuthServer.Infrastructure.Constants;
    using AuthServer.Infrastructure.Data.Identity;
    using IdentityModel;
    using IdentityServer4;
    using IdentityServer4.Extensions;
    using IdentityServer4.Models;
    using IdentityServer4.Services;
    using Microsoft.AspNetCore.Identity;
    
    namespace AuthServer.Infrastructure.Services
    {
        public class IdentityClaimsProfileService : IProfileService
        {
            private readonly IUserClaimsPrincipalFactory<AppUser> _claimsFactory;
            private readonly UserManager<AppUser> _userManager;
    
            public IdentityClaimsProfileService(UserManager<AppUser> userManager, IUserClaimsPrincipalFactory<AppUser> claimsFactory)
            {
                _userManager = userManager;
                _claimsFactory = claimsFactory;
            }
    
            public async Task GetProfileDataAsync(ProfileDataRequestContext context)
            {
                var sub = context.Subject.GetSubjectId();
                var user = await _userManager.FindByIdAsync(sub);
                var principal = await _claimsFactory.CreateAsync(user);
    
                var claims = principal.Claims.ToList();
                claims = claims.Where(claim => context.RequestedClaimTypes.Contains(claim.Type)).ToList();
                claims.Add(new Claim(JwtClaimTypes.GivenName, user.Name));
                claims.Add(new Claim(IdentityServerConstants.StandardScopes.Email, user.Email));
                // note: to dynamically add roles (ie. for users other than consumers - simply look them up by sub id
                claims.Add(new Claim(ClaimTypes.Role, Roles.Consumer)); // need this for role-based authorization - https://stackoverflow.com/questions/40844310/role-based-authorization-with-identityserver4
    
                context.IssuedClaims = claims;
            }
    }
    

    【讨论】:

    • 我了解如何从经过身份验证的用户那里提取声明,问题是存储在数据库表AspNetUserClaims 中的声明没有被拉入声明列表。我只取回默认声明和角色列表。 var claims = User.Claims.Select(c =&gt; new { c.Type, c.Value }); 实际上与我在问题中发布的行相同:var claims = ((ClaimsIdentity)User.Identity).Claims;
    • 我明白了,我更新了我的答案。它可能很有用,但需要更多配置。
    • 我尝试设置自定义配置文件服务,但这不会影响传递到客户端应用程序的声明。此外,看起来这个答案对动态声明没有帮助,只有在用户实体中具有隐式命名和配置的声明。
    【解决方案2】:

    您是否有一个 IProfileService 实现来填充您的自定义声明?

    您应该按照answer 中的说明实现IProfileService

    尝试其他response_type 而不是id_token,因为您的应用程序没有访问令牌来调用用户信息端点。也许用id_token token 来维护您客户的隐式流量授权。

    【讨论】:

    • 我尝试实现 IProfileService 并在配置服务中注册,但这似乎并没有影响到客户端应用程序的声明。我错过了什么吗?
    • 您使用的是response_type=id_token。您没有获得访问令牌,并且您的处理程序需要访问令牌来调用用户信息端点。你试过其他response_type吗?
    • 我已尝试使用替代响应类型,包括建议的响应类型(id_token 令牌),但这并没有带来额外的声明。
    • 原来我错过了一步,配置文件服务必须在我的身份配置和依赖项中注册。即'services.AddIdentityServer().AddProfileService&lt;CustomProfileService&gt;()...;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-15
    • 1970-01-01
    • 2017-11-14
    • 2021-12-18
    • 2019-02-07
    • 1970-01-01
    • 2016-01-10
    相关资源
    最近更新 更多