基于请求参数的 OWIN 中 JWT 的用户特定秘密

User specific secret for JWT in OWIN based on request parameter

我创建了一个示例身份服务。它从配置文件中读取一个密钥。

ConfigurationManager.AppSettings["as:AudienceSecret"]

我需要修改它以根据传入请求的正文参数 (form["CurrentUser"]) 从数据库中读取秘密。我们该怎么做?

Startup.cs 配置

    private void ConfigureOAuthTokenGeneration(IAppBuilder app)
    {

        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);

        string issuer = ConfigurationManager.AppSettings["Issuer"];
        OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
        {

            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/oauth/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new CustomOAuthProvider(),
            AccessTokenFormat = new CustomJwtFormat(issuer)
        };

        // OAuth 2.0 Bearer Access Token Generation
        app.UseOAuthAuthorizationServer(OAuthServerOptions);
    }
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
        {
            string issuer = ConfigurationManager.AppSettings["Issuer"];

            string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
            byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:AudienceSecret"]);

        app.UseJwtBearerAuthentication(
            new JwtBearerAuthenticationOptions
            {
                AuthenticationMode = AuthenticationMode.Active,
                AllowedAudiences = new[] { audienceId },
                IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                {
                    new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
                }
            });
    }

CustomOAuthProvider 中的 GrantResourceOwnerCredentials

 public override async Task
 GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{

    var allowedOrigin = ConfigurationManager.AppSettings["AllowedOrigin"];
    context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
    var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();


    ApplicationUser user = null;
    try
    {
        user = await userManager.FindAsync(context.UserName, context.Password);
    }
    catch (Exception ex)
    {
        string result = ex.Message;
        string innerText = ex.InnerException.ToString();
    }

    if (user == null)
    {
        context.SetError("invalid_grant", "The user name or password is incorrect.");
        return;
    }

    var form = await context.Request.ReadFormAsync();
    var loggedinUserName = form["CurrentUser"];
    string practice = null;
    if (!String.IsNullOrWhiteSpace(loggedinUserName))
    {
        ApplicationUser loggedinUserObj = userManager.FindByName(loggedinUserName);
        string loggedinUserID = loggedinUserObj == null ? "" : loggedinUserObj.Id;

        if (loggedinUserID != null)
        {
            ProvidersBL providersBL = new ProvidersBL();
            practice = providersBL.GetPracticeForUser(loggedinUserID);
        }
    }

    practice = practice ?? "Undefined";
    loggedinUserName = loggedinUserName ?? "Undefined";


    var claims = new List<Claim>();
    claims.Add(new Claim(ClaimTypes.Name, loggedinUserName));
    claims.Add(new Claim("Practice", practice));
    var oAuthIdentity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
    var ticket = new AuthenticationTicket(oAuthIdentity, null);
    context.Validated(ticket);

}

以下作品。不确定这是否是最佳解决方案。

注意:我后来决定不为不同的用户使用不同的密钥。所有用户的密钥都相同。但是作为声明,令牌中的每个用户都会插入一个用户特定的密钥。一旦用户使用一次,该密钥将在数据库中刷新。下一次,对于同一用户,令牌中的用户密钥将不同。

    public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
    {

        private readonly string _issuer = string.Empty;
        private ProvidersBL providerBL;
        public CustomJwtFormat(string issuer)
        {
            _issuer = issuer;
            providerBL = new ProvidersBL();
        }

        public string Protect(AuthenticationTicket data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            string userName = String.Empty;
            var userNameClaim = data.Identity.Claims.FirstOrDefault(claim => claim.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name");
            if (userNameClaim != null)
            {
                userName = userNameClaim.Value;
            }


            string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
            string symmetricKeyAsBase64 = string.Empty;
            symmetricKeyAsBase64 = providerBL.GetKeyForUser(userName);
            if (String.IsNullOrWhiteSpace(symmetricKeyAsBase64))
            {
                symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
            }


            var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
            var signingKey = new HmacSigningCredentials(keyByteArray);


            var issued = data.Properties.IssuedUtc;
            var expires = data.Properties.ExpiresUtc;
            var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
            var handler = new JwtSecurityTokenHandler();
            var jwt = handler.WriteToken(token);
            return jwt;
        }

        public AuthenticationTicket Unprotect(string protectedText)
        {
            throw new NotImplementedException();
        }
    }