如何自定义 ASP .NET Web API JWT 令牌响应?

Posted

技术标签:

【中文标题】如何自定义 ASP .NET Web API JWT 令牌响应?【英文标题】:How to customize ASP .NET Web API JWT token response? 【发布时间】:2021-01-28 18:17:13 【问题描述】:

我正在使用带有 Web API 的 Asp.net Webform 项目。我配置了基于 JWT 令牌的身份验证,现在我想自定义身份验证响应

这是我的配置,

    Startup.cs

    public class Startup
    
         public void Configuration(IAppBuilder app)
         
             HttpConfiguration config = new HttpConfiguration();
    
             // Web API routes
             config.MapHttpAttributeRoutes();
    
             app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    
             ConfigureOAuth(app);
    
             app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    
             WebApiConfig.Register(config);
    
         
    
         public void ConfigureOAuth(IAppBuilder app)
         
    
             String apiHttpOnly = ConfigurationManager.AppSettings["AllowInsecureHttp"];
             String tokenTimeSpan = ConfigurationManager.AppSettings["tokenTimeSpanFromMinutes"];
    
             bool allowInsecureHttp = !String.IsNullOrEmpty(apiHttpOnly) ? 
                                      Convert.ToBoolean(apiHttpOnly) : false;
             int accessTokenExpireTimeSpan = !String.IsNullOrEmpty(tokenTimeSpan) ? 
                                      Convert.ToInt32(tokenTimeSpan) : 60;
    
             var authProvider = new AuthorizationServiceProvider();
             OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions
             
                 //For Dev enviroment only (on production should be AllowInsecureHttp = false)
                 AllowInsecureHttp = allowInsecureHttp,
                 TokenEndpointPath = new PathString("/api/authenticate"),
                 AccessTokenExpireTimeSpan = TimeSpan.FromDays(accessTokenExpireTimeSpan),
                 Provider = authProvider
             ;
    
             app.UseOAuthAuthorizationServer(options);
    
         
    
    

    授权服务提供者

     public class AuthorizationServiceProvider : OAuthAuthorizationServerProvider
     
         public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
         
             context.Validated();
             return base.ValidateClientAuthentication(context);
         
    
         public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
         
             var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    
             if (Membership.ValidateUser(context.UserName, context.Password))
             
                 identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
                 identity.AddClaim(new Claim("username", context.UserName));
                 identity.AddClaim(new Claim(ClaimTypes.Name, "admin admin"));
                 context.Validated(identity);
             
             else
             
                 context.SetError("invalid_grant", "Provide username and password is incorrect.");
    
             
    
             return base.GrantResourceOwnerCredentials(context);
         
     
    

当我使用正确的凭据调用 API 时,它会返回


    "access_token": "uEwmXl6N0mJXVUZesxA_2tG5lIuZUIUDaxtjAl0QGE6j2-J7n4c63zboOUClGjRQf1IDY9-nBgyq0HP5WR7MMxTYoHGIyiHIbcKu9AYwhECCGaVBCxY2Ounhit4N1pYK1vV6uX6AcoA-a0xhytF8Jz27D77ZvCLi3PuUQDEXSp0pkGG796wu1fRZCaRsCB-kLoa-_V7KJaGGhhoybN_c0GNOBhhwmGpx6Js26-Vx-lmWpfsPUE1aKrJfx-oMcyE5x7CooAlx4vA6iZhnNfmYdRejRKoKKnObyuAsym7mVdZY3bpv",
    "token_type": "bearer",
    "expires_in": 5183999

我想通过添加一些额外的属性来自定义响应,例如,


    "access_token": "uEwmXl6N0mJXVUZesxA_2tG5lIuZUIUDaxtjAl0QGE6j2-J7n4c63zboOUClGjRQf1IDY9-nBgyq0HP5WR7MMxTYoHGIyiHIbcKu9AYwhECCGaVBCxY2Ounhit4N1pYK1vV6uX6AcoA-a0xhytF8Jz27D77ZvCLi3PuUQDEXSp0pkGG796wu1fRZCaRsCB-kLoa-_V7KJaGGhhoybN_c0GNOBhhwmGpx6Js26-Vx-lmWpfsPUE1aKrJfx-oMcyE5x7CooAlx4vA6iZhnNfmYdRejRKoKKnObyuAsym7mVdZY3bpv",
    "token_type": "bearer",
    "expires_in": 5183999,
    "attribute1" : "abc",
    "attribute2" : "ert"

有人有这个想法吗?

【问题讨论】:

【参考方案1】:

最后,我调查问题并找出解决方案。我把它贴在这里,也许它可以帮助别人。

    添加身份验证属性

    var props = new AuthenticationProperties(new Dictionary<string, string>
    
        
             "attribute1" , "abc"
        ,
        
             "attribute2" , "ert"
        
    );
    

    然后使用 AuthenticationTicket

    创建 Ticket
    var ticket = new AuthenticationTicket(identity, props);
    

    将票证添加到上下文

    context.Validated(ticket);
    

    然后实现覆盖方法TokenEndpoint

     public override Task TokenEndpoint(OAuthTokenEndpointContext context)
     
         foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
         
             context.AdditionalResponseParameters.Add(property.Key, property.Value);
         
         return Task.FromResult<object>(null);
     
    

最后是AuthorizationServiceProvider类,

public class AuthorizationServiceProvider : OAuthAuthorizationServerProvider

    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    
        context.Validated();
        return base.ValidateClientAuthentication(context);
    

    public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    
        var identity = new ClaimsIdentity(context.Options.AuthenticationType);

        if (string.IsNullOrEmpty(context.UserName) || string.IsNullOrEmpty(context.Password))
        
            context.SetError("invalid_request", "No username or password are provided.");
        
        else if (Membership.ValidateUser(context.UserName, context.Password))
        
            
            identity.AddClaim(new Claim("username", context.UserName));
            identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));

            /*
             * All custom response props are define here.
             * --------usage----------
             * use as dictionary
             * */
            var props = new AuthenticationProperties(new Dictionary<string, string>
            
                //
                //    "test" , "val"
                //
            );

            var ticket = new AuthenticationTicket(identity, props);


            context.Validated(ticket);
        
        else
        
            context.SetError("invalid_grant", "Provide username and password is incorrect.");

        

        return base.GrantResourceOwnerCredentials(context);
    

    public override Task TokenEndpoint(OAuthTokenEndpointContext context)
    
        foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
        
            context.AdditionalResponseParameters.Add(property.Key, property.Value);
        
        return Task.FromResult<object>(null);
    

更多信息 - https://***.com/a/26369622/8403632

示例 - https://github.com/Leftyx/OwinWebApiBearerToken

【讨论】:

以上是关于如何自定义 ASP .NET Web API JWT 令牌响应?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 asp.net web api 2 中自定义对我自己的一组表的身份验证?

如何在 Asp.NET Core WEB API 中使用 .Net (C#) 在 Payload 中创建具有自定义 JSON 声明的 JWT 令牌

ASP.NET Web Api 路由自定义

Asp.Net Core Web API 5.0 和 Angular 中基于自定义角色的授权

asp.net web api添加自定义认证

ASP.NET web api - 设置自定义 IIdentity 或 IPrincipal