[英]How to Customize JWT token validation in oAuth 2.0 / owin?
我正在嘗試使用oAuth 2.0中間件驗證JWT。 我嘗試在Startup.cs類中使用自定義提供程序:
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
}
}
在繼承IOAuthBearerAuthenticationProvider的CustomOAuthBearerProvider中,我提供了ApplyChallenge(),RequestToken()和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);
}
}
現在,當我嘗試獲取授權資源時,首先會命中RequestToken(),然后我不知道JWT是如何進行驗證的,並將控制權傳遞給ValidateIdentity()方法。
我要自定義驗證過程的原因是為了保存和延長數據庫中JWT的過期時間(您也可以提出任何建議來增加JWT的過期時間而無需更改原始令牌)。
請發表評論,無論您認為什么想法/建議/好/不好的做法/鏈接都將有所幫助。 謝謝。
實際上,我們可以進行JWT的自定義驗證。 我創建了一個沒有到期時間的JWT,並通過其簽名對其進行了驗證,當我們將到期時間保留在我們的Jwt中時,也可以這樣做。 現在像之前一樣,我們可以使用OAuthBearerAuthentication , 而不是使用JWTBearerAuthentication,如下所示:
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
}
而且,您可以使用相同的CustomJwtFormat類來創建您的JWT,以通過在ISecureDataFormat接口中聲明的UnProtect方法來驗證JWT:
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
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.