OpenID Connect:如何在客户端凭证流中添加自定义声明数据

Posted

技术标签:

【中文标题】OpenID Connect:如何在客户端凭证流中添加自定义声明数据【英文标题】:OpenID Connect: How to add custom claims data in the client credential flow 【发布时间】:2020-08-19 19:51:22 【问题描述】:

我正在使用我的身份服务器设置客户端凭据流,以从客户端获取访问令牌。我可以使用以下代码获取访问令牌,

身份服务器配置:

 public void Configuration(IAppBuilder app)

    app.Map("/identity", idsrvApp =>
    
        var corsPolicyService = new DefaultCorsPolicyService()
        
            AllowAll = true
        ;

        var idServerServiceFactory = new IdentityServerServiceFactory()
        .UseInMemoryClients(Clients.Get())
        .UseInMemoryScopes(Scopes.Get())
        .UseInMemoryUsers(Users.Get());

        var options = new IdentityServerOptions
        
            Factory = idServerServiceFactory,
            SiteName = "Demo",
            IssuerUri = IdentityConstants.IssuerUri,
            PublicOrigin = IdentityConstants.STSOrigin,
            SigningCertificate = LoadCertificate()
        ;

        idsrvApp.UseIdentityServer(options);
    );

身份服务器 - 客户端配置:

public static class Clients

    public static IEnumerable<Client> Get()
    
    return new[]
     
        new Client
        
             ClientId = "ClientSDK",
             ClientName = "Client SDK (Client Credentials)",
             Flow = Flows.ClientCredentials,
             AllowAccessToAllScopes = true,

            ClientSecrets = new List<Secret>()
            
                new Secret(IdentityConstants.ClientSecret.Sha256())
            
        
     ;

MVC 客户端:

  var oAuth2Client = new TokenClient(
              IdentityConstants.STSTokenEndpoint,
              "ClientSDK",
                IdentityConstants.ClientSecret);

    var tokenResponse = oAuth2Client.RequestClientCredentialsAsync("MyScope").Result;

    return tokenResponse.AccessToken;

我可以获得访问令牌(即 JWT)。谁能告诉我如何在创建令牌时使用其声明数据创建 JWT 时,如何从我的数据库中添加一个唯一键,例如 (UserId)。

【问题讨论】:

@你已经配置了内存用户,你想从你的应用程序数据库中验证用户并从数据库中添加对令牌的声明吗? 【参考方案1】:

首先,您需要在 Azure 门户上创建自定义属性“userId”,并将其应用于选定的应用程序。然后按照这个例子, Update user using Graph API

如果您使用的是内置用户流,则需要为您的应用程序选择“userId”。 如果您使用的是自定义策略,请遵循以下流程。 JWT 令牌仅显示 Azure AD B2C 自定义策略的输出声明。创建和更新自定义策略是一个多步骤过程。这里是阅读更多关于How to create custom attribute的链接

【讨论】:

【参考方案2】:

您应该实现自定义用户存储以验证用户并从数据库添加声明。如下更改启动代码,Userrepository 类代表数据库通信以验证用户并从数据库获取声明:

var idServerServiceFactory = new IdentityServerServiceFactory()
   .UseInMemoryClients(Clients.Get())
   .UseInMemoryScopes(Scopes.Get())
   .AddCustomUserStore();

添加以下类并根据您的要求进行更改:

public static class CustomIdentityServerBuilderExtensions

    public static IIdentityServerBuilder AddCustomUserStore(this IIdentityServerBuilder builder)
                       
        builder.AddProfileService<UserProfileService>();           
        builder.AddResourceOwnerValidator<UserResourceOwnerPasswordValidator>();
        return builder;
    


public class UserProfileService : IProfileService

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    
            UserRepository userRepository=new UserRepository();
            var user = userRepository.GetUserById(int.Parse(context.Subject.GetSubjectId()));
            if (user != null)
            
                var userTokenModel = _mapper.Map<UserTokenModel>(user);
                var claims = new List<Claim>();
                claims.Add(new Claim("UserId", user.UserId));
                // Add another claims here 
                context.IssuedClaims.AddRange(claims);                    
    
    public async Task IsActiveAsync(IsActiveContext context)
              
    


public class UserResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
        
    public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
               
            UserRepository userRepository=new UserRepository();
            var userLoginStatus = userRepository.GetUserById(context.UserName, context.Password);

            if (userLoginStatus != null)
            

                    context.Result = new GrantValidationResult(userLoginStatus.UserId.ToString(),
                         OidcConstants.AuthenticationMethods.Password);                   
            
            else
                                
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidClient, 
                        "Wrong Credentials");
                        
    

【讨论】:

以上是关于OpenID Connect:如何在客户端凭证流中添加自定义声明数据的主要内容,如果未能解决你的问题,请参考以下文章

OpenID Connect 服务器流中的“state”参数可以防止啥攻击?

如何确定用户是不是仍在使用 PingFederate OpenID Connect 隐式客户端流登录?

OpenId Connect 如何保护资源服务器免受客户端模拟?

使用 openid connect 时如何确保客户端服务的 GDPR/ToS 合规性?

如何验证每个用户可以使用 OAuth 和 OpenID Connect 访问哪些资源?

Oauth2 - 客户端凭证流中的长寿命令牌与重新身份验证