2016-04-14 13 views
2

Ich versuche, eine JWT mit oAuth 2.0 Middleware zu validieren. Ich habe versucht, einen benutzerdefinierten Provider in meiner Startup.cs-Klasse:Wie Anpassen der JWT-Token-Validierung in OAuth 2.0/owin?

public class Startup 
{ 
    public void Configuration(IAppBuilder app) 
    { 
     HttpConfiguration config = new HttpConfiguration(); 

     // Web API routes 
     config.MapHttpAttributeRoutes(); 

     ConfigureOAuth(app); 

     app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); 

     app.UseWebApi(config); 

    } 

    public void ConfigureOAuth(IAppBuilder app) 
    { 

     OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() 
     { 
      //For Dev enviroment only (on production should be AllowInsecureHttp = false) 
      AllowInsecureHttp = true, 
      TokenEndpointPath = new PathString("/oauth2/token"), 
      AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(5), 
      Provider = new CustomOAuthProvider(), 
      AccessTokenFormat = new RMAJwtAuthenticator.CustomJwtFormat("www.abc.com") 
     }; 

     // OAuth 2.0 Bearer Access Token Generation 
     app.UseOAuthAuthorizationServer(OAuthServerOptions); 

     // start : Code for Validating JWT 
     var issuer = "www.abc.com"; 
     var audience = "www.xyz.com"; 
     var secret = TextEncodings.Base64Url.Decode("Yuer534553HDS&dsa"); 

     // Api controllers with an [Authorize] attribute will be validated with JWT 
     app.UseJwtBearerAuthentication(
      new JwtBearerAuthenticationOptions 
      { 
       AuthenticationMode = AuthenticationMode.Active, 
       AllowedAudiences = new[] { audience }, 
       IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[] 
       { 
        new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret) 
       }, 
       Provider = new CustomOAuthBearerProvider() 


      }); 

     //End: Code for Validating JWT 

    } 
} 

In meinem CustomOAuthBearerProvider der IOAuthBearerAuthenticationProvider erbt, sofern ich die defination von ApplyChallenge(), RequestToken() und ValidateIdentity():

public class CustomOAuthBearerProvider : IOAuthBearerAuthenticationProvider 
{ 
    public Task ApplyChallenge(OAuthChallengeContext context) 
    {    
     return Task.FromResult<object>(null); 
    } 

    public Task RequestToken(OAuthRequestTokenContext context) 
    {    
     return Task.FromResult<object>(null); 
    } 

    public Task ValidateIdentity(OAuthValidateIdentityContext context) 
    {    
     return Task.FromResult<object>(null); 
    } 
} 

Jetzt, wenn ich versuche, eine Autorisierte Ressource zu bekommen, bekomme zuerst RequestToken() und dann weiß ich nicht, wie JWT validiert wurde und die Kontrolle an die ValidateIdentity() Methode übergeben wurde.

Der Grund, warum ich den Validierungsprozess anpassen möchte, ist das Speichern und Erweitern der Ablaufzeit meines JWT in der Datenbank (Sie können auch alles vorschlagen, um die Ablaufzeit eines JWT zu erhöhen, ohne das ursprüngliche Token zu ändern).

Bitte kommentieren Sie, was auch immer Gedanken/Vorschläge/gut-schlechte Übung Optionen/Links, die Sie fühlen, wird hilfreich sein. Danke.

Antwort

3

Eigentlich können wir die benutzerdefinierte Validierung von JWT machen. Ich habe ein JWT ohne Ablaufzeit erstellt und es durch seine Signatur validiert. Dies kann auch geschehen, wenn wir die Ablaufzeit in unserem JWT halten. wie jetzt früher, statt JWTBearerAuthentication zu verwenden, können wir OAuthBearerAuthentication wie unten verwenden:

public void ConfigureOAuth(IAppBuilder app) 
    { 
     OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() 
     { 
      //For Dev enviroment only (on production should be AllowInsecureHttp = false) 
      AllowInsecureHttp = true, 
      TokenEndpointPath = new PathString("/api/token"), 
      //provide Expire Time 
      //AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(5), 
      Provider = new CustomOAuthProvider(), 
      //provide issuer name/url 
      // 
      AccessTokenFormat = new RMAJwtAuthenticator.CustomJwtFormat("www.abc.com") 
     }; 

     // OAuth 2.0 Bearer Access Token Generation 
     app.UseOAuthAuthorizationServer(OAuthServerOptions); 

     //// start : Code for Validating JWT 

     OAuthBearerAuthenticationOptions OAuthBearerOptions = new OAuthBearerAuthenticationOptions() 
     { 
      AccessTokenFormat = OAuthServerOptions.AccessTokenFormat, 
      AccessTokenProvider = OAuthServerOptions.AccessTokenProvider, 
      AuthenticationMode = OAuthServerOptions.AuthenticationMode, 
      AuthenticationType = OAuthServerOptions.AuthenticationType, 
      Description = OAuthServerOptions.Description, 
      Provider = new CustomOAuthBearerProvider() 
     }; 
     app.UseOAuthBearerAuthentication(OAuthBearerOptions); 

     //////End: Code for Validating JWT 

    } 

Und können Sie gleiche CustomJwtFormat Klasse verwenden, die Ihre JWT erstellt Ihre JWT durch unprotect Methode zu validieren, die ist in ISecureDataFormat-Schnittstelle deklariert:

public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket> 
{ 
    //Needs to be configured in Configuration file 
    const string AudiencePropertyKey = "audience"; 
    const string signatureAlgorithm = "www.w3.org/2001/04/xmldsig-more#hmac-sha256"; 
    const string digestAlgorithm = "www.w3.org/2001/04/xmlenc#sha256"; 

    private readonly string _issuer = string.Empty; 

    public CustomJwtFormat(string issuer) 
    { 
     _issuer = issuer; 
    } 

    /// <summary> 
    /// Creates JWT Token here, using AuthenticationTicket 
    /// </summary> 
    /// <param name="data"></param> 
    /// <returns></returns> 
    public string Protect(AuthenticationTicket data) 
    { 
     JwtAuthHelper objJwtAuthHelper = new JwtAuthHelper(); 
     try 
     { 
      if (data == null) 
      { 
       throw new ArgumentNullException("data"); 
      } 

      string audienceId = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null; 

      if (string.IsNullOrWhiteSpace(audienceId)) throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience"); 

      //check if audience is valid (in case of audience is stored in DB or some list) 
      Audience audience = AudiencesStore.FindAudience(audienceId); 

      //In case , if each audience has separate secretKey 
      //Right now we have a common secret key 
      if (audience != null) 
      { 
       var symmetricKey = TextEncodings.Base64Url.Decode(audience.EncryptedSecret);//any encrypted (or simple) key from 3rd party client 

       //***added refernce of System.IdenityModel to get SigningCredentials class refernce 
       // instead of using ThinkTecture nugget packaged dlls 
       var SigningCredentials = new SigningCredentials(new InMemorySymmetricSecurityKey(symmetricKey), signatureAlgorithm, digestAlgorithm); 

       var issued = data.Properties.IssuedUtc; 
       var expires = data.Properties.ExpiresUtc; 

       //Modified to keep issued and expirey time as NULL 
       var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, null, null, SigningCredentials); 
       //var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, SigningCredentials); 

       var handler = new JwtSecurityTokenHandler(); 

       var jwt = handler.WriteToken(token); 

      } 

      return string.Empty; 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

    /// <summary> 
    /// UnProtect ticket : Validates JWT 
    /// </summary> 
    /// <param name="protectedText"></param> 
    /// <returns></returns> 
    public AuthenticationTicket Unprotect(string protectedText) 
    { 
     // start : Code for Validating JWT      

     //JwtSecurityTokenHandler 
     System.IdentityModel.Tokens.JwtSecurityTokenHandler tokenHandler = new System.IdentityModel.Tokens.JwtSecurityTokenHandler(); 
     System.Security.Claims.ClaimsPrincipal claimsPrincipal; 

     try 
     { 
      System.IdentityModel.Tokens.JwtSecurityToken tokenReceived = new System.IdentityModel.Tokens.JwtSecurityToken(protectedText); 

      //Configure Validation parameters// Now its Generalized//token must have issuer and audience 
      var issuer = tokenReceived.Issuer; 
      List<string> strAudience = (List<string>)tokenReceived.Audiences; 
      var audience = strAudience.Count > 0 ? strAudience[0].ToString(): string.Empty; 
      Audience audForContext = AudiencesStore.FindAudience(audience); 
      var symmetricKey = Microsoft.Owin.Security.DataHandler.Encoder.TextEncodings.Base64Url.Decode(audForContext.EncryptedSecret); 

      var validationParameters = new System.IdentityModel.Tokens.TokenValidationParameters() 
      { 
       ValidAudience = audience, 
       IssuerSigningKey = new System.IdentityModel.Tokens.InMemorySymmetricSecurityKey(symmetricKey), 
       ValidIssuer = issuer, 
       RequireExpirationTime = false 
      }; 

      System.IdentityModel.Tokens.SecurityToken validatedToken;     
      //if token gets validated claimsPrincipal has value otherwise it throws exception     
      claimsPrincipal = tokenHandler.ValidateToken(protectedText, validationParameters, out validatedToken); 

      var props = new AuthenticationProperties(new Dictionary<string, string> { { "audience", audience } }); 
      var ticket = new AuthenticationTicket((System.Security.Claims.ClaimsIdentity)claimsPrincipal.Identity, props); 
      return ticket; 
     } 
     catch (Exception) 
     { 

      throw; 
     } 

     ////End: Custom code to handle Validate Token 
    } 

}