2017-02-24 39 views
0

我已經創建了示例身份服務。它從配置文件中讀取密鑰。OWIN中基於請求參數的JWT的用戶特定祕密

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) 
       } 
      }); 
    } 

GrantResourceOwnerCredentials在CustomOAuthProvider

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); 

} 
+0

爲什麼你需要這個?祕密在於確認應用程序(客戶端)不是用戶 –

+0

@CallbackKid [JWT每用戶簽名密鑰](https://auth0.com/forum/t/jwt-per-user-signing-key/485)說:「你提到的方法絕對是有效的。」 – Lijo

+0

另一個參考:[帶有JWT的單次使用令牌](https://www.jbspeakr.cc/howto-single-use-jwt/) – Lijo

回答

0

以下工作。不知道這是否是最好的解決方案。

注意:我後來決定不爲不同的用戶使用不同的密鑰。所有用戶的密鑰都是一樣的。但是會爲權標內的每個用戶插入一個用戶特定的密鑰作爲聲明。一旦用戶使用過一次,該密鑰將在數據庫中刷新。下一次,對於同一個用戶,該用戶密鑰在令牌中會有所不同。

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(); 
     } 
    } 
相關問題