如何使用ClientAssertion定义AuthorizationCodeTokenRequest

问题描述

我正在尝试弄清楚如何为代码流定义AuthorizationCodetokenRequest 对于JWT场景,使用IdentityModole框架

假设我在OP服务器上有一个已定义的客户端


new Client
{
ClientId = "myClientId"
ClientSecrets = {
new Secret("MyVerySpecialSecret".Sha256())
}

客户端上的

我想使用 JWT

获得AuthorizationCode
        var securityToken = tokenHandler.CreateJwtSecurityToken(
            issuer: clientID,audience: opEndPoint.TokenEndpoint,subject: new ClaimsIdentity(new List<Claim>()
            {
                        new Claim(JwtClaimTypes.JwtId,Guid.NewGuid().ToString()),new Claim(JwtClaimTypes.Subject,clientID),new Claim(JwtClaimTypes.IssuedAt,new DateTimeOffset(Now).ToEpochTime().ToString(),ClaimValueTypes.integer64)
            }),expires:Now.AddMinutes(5),signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MyVerySpecialSecret")),SecurityAlgorithms.HmacSha256Signature)
        );

        var clientAuthJwt = tokenHandler.Writetoken(securityToken);
var request = new AuthorizationCodetokenRequest()
{
Address = opEndPoint.TokenEndpoint,ClientId = clientID,Code = code,ClientAssertion = new ClientAssertion()
{
Type = OidcConstants.ClientAssertionTypes.JwtBearer,Value = clientAuthJwt
},RedirectUri = opEndPoint.RedirectUri,GrantType = OidcConstants.GrantTypes.AuthorizationCode
};

    var response = client.RequestAuthorizationCodetokenAsync(request).Result;

我正在获取“ invalid_client”,所以很明显我正在使用的SigningCredentials不正确 在任何地方都找不到有效的代码示例。

解决方法

首先,您需要在IdentityServer的“客户端定义”中定义希望客户端支持的流。

您可以通过设置以下属性来做到这一点:

AllowedGrantTypes = GrantTypes.Code,

有关如何正确创建客户定义的详细信息,请参见here

示例客户端如下所示:

       var client2 = new Client
        {
            ClientId = "authcodeflowclient",//Unique ID of the client
            ClientName = "AuthCodeFlow Client",//Client display name (used for logging and consent screen)
            ClientUri = "https://www.edument.se",//URI to further information about client (used on consent screen)
            RequirePkce = true,AllowOfflineAccess =true,ClientSecrets = new List<Secret>
            {
                new Secret
                {
                    Value = "mysecret".Sha512()
                }
            },AllowedGrantTypes = GrantTypes.Code,// When requesting both an id token and access token,should the user claims always
            // be added to the id token instead of requiring the client to use the userinfo endpoint.
            // Defaults to false.
            AlwaysIncludeUserClaimsInIdToken = false,//Specifies whether this client is allowed to receive access tokens via the browser. 
            //This is useful to harden flows that allow multiple response types 
            //(e.g. by disallowing a hybrid flow client that is supposed to  use code id_token to add the token response type and thus leaking the token to the browser.
            AllowAccessTokensViaBrowser = false,RedirectUris =
            {
                "https://localhost:5001/CodeFlow/Callback","https://localhost:5001/RefreshToken/Callback","https://localhost:5001/signin-oidc"
            },PostLogoutRedirectUris = { "https://localhost:5001/signout-callback-oidc" },// By default a client has no access to any resources
            // specify the allowed resources by adding the corresponding scopes names.
            // If empty,the client can't access any scope
            AllowedScopes =
            {
                //Standard scopes
                IdentityServerConstants.StandardScopes.OpenId,IdentityServerConstants.StandardScopes.Email,IdentityServerConstants.StandardScopes.Profile,IdentityServerConstants.StandardScopes.Phone,"employee_info","shop.admin","shop.employee","shop.guest"
            },AllowedCorsOrigins =
            {
                "https://localhost:5001"
            }
        };

SigningCredentials是一个单独的事物,它控制如何发行IdentityServer发行的密钥。在开发过程中,您无需担心,因为在调用此方法时,所有这些都得到了照顾。 builder.AddDeveloperSigningCredential();

在部署IdentityServer时,您只需要处理SigningCredentials。

客户端,您需要在ASP.NET Core客户端应用程序中编写如下所示的代码:

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        }).AddCookie(options =>
        {
            options.LoginPath = "/User/Login";
            options.LogoutPath = "/User/Logout";
            options.AccessDeniedPath = "/User/AccessDenied";
        }).AddOpenIdConnect(options =>
        {
            options.Authority = "https://localhost:6001";
            options.ClientId = "authcodeflowclient";
            options.ClientSecret = "mysecret";
            options.ResponseType = "code";

            options.Scope.Clear();
            options.Scope.Add("openid");
            options.Scope.Add("profile");
            options.Scope.Add("email");
            options.Scope.Add("employee_info");



            options.SaveTokens = true;
            options.SignedOutRedirectUri = "/";
            options.GetClaimsFromUserInfoEndpoint = true;

            options.TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = JwtClaimTypes.Name,RoleClaimType = JwtClaimTypes.Role,};

            options.Prompt = "consent";
        });

您需要调整代码以适合您的需求。