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

How to customize ASP .NET Web API JWT token response?

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

这是我的配置,

  1. 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);
    
         }
    }
    
  2. 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 (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 时,它 returns 就像

{
    "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. 添加AuthenticationProperties

    var props = new AuthenticationProperties(new Dictionary<string, string>
    {
        {
             "attribute1" , "abc"
        },
        {
             "attribute2" , "ert"
        }
    });
    
  2. 然后使用 AuthenticationTicket

    创建 Ticket
    var ticket = new AuthenticationTicket(identity, props);
    
  3. 将工单添加到 上下文

    context.Validated(ticket);
    
  4. 然后实现覆盖方法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 class 就像,

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://github.com/Leftyx/OwinWebApiBearerToken