有人可以提供示例C#.NET代码来验证由WSO2 API网关发布的JWT,该网关使用SHA256withRSA算法进行签名。我非常确定我需要设置TokenValidationParameters.IssuerSigningToken,然后调用JwtSecurityTokenHandler.ValidateToken方法,但我还没有能够让它工作,或找到任何示例代码。
这是我到目前为止所做的:
// Use JwtSecurityTokenHandler to validate the JWT token
var tokenHandler = new JwtSecurityTokenHandler();
var convertedSecret = EncodeSigningToken(ConfigurationManager.AppSettings["ClientSecret"]);
// Read the JWT
var parsedJwt = tokenHandler.ReadToken(token);
// Set the expected properties of the JWT token in the TokenValidationParameters
var validationParameters = new TokenValidationParameters()
{
NameClaimType = "http://wso2.org/claims/enduser",
AuthenticationType = "http://wso2.org/claims/usertype",
ValidAudience = ConfigurationManager.AppSettings["AllowedAudience"],
ValidIssuer = ConfigurationManager.AppSettings["Issuer"],
IssuerSigningToken = new BinarySecretSecurityToken(convertedSecret)
};
var claimsPrincipal = tokenHandler.ValidateToken(token, validationParameters, out parsedJwt);
答案 0 :(得分:2)
WSO2 API网关中的JWT不遵循规范(https://tools.ietf.org/html/rfc7519)。
我见过的所有样本都是以下形式:
<Base64lEncodedHeader>.<Base64EncodedPayload>.<OPTIONAL, Base64EncodedSignature>
但应该是:
<Base64UrlEncodedHeader>.<Base64UrlEncodedPayload>.<OPTIONAL, Base64UrlEncodedSignature>
问题是使用Base64而不是Base64Url编码。由于签名基于<Base64EncodedHeader>.<Base64EncodedPayload>
,并且MS JWT框架正在根据预期的<Base64UrlEncodedHeader>.<Base64UrlEncodedPayload>
验证签名,因此它将始终无法通过验证。我必须编写自己的自定义签名验证码来解决此问题。然后,在使用JwtSecurityTokenHandler解析和解码之前,我从令牌中剥离签名。
以下是最终代码:
try
{
// Get data and signature from unaltered token
var data = Encoding.UTF8.GetBytes(token.Split('.')[0] + '.' + token.Split('.')[1]);
var signature = Convert.FromBase64String(token.Split('.')[2]);
// Get certificate from file
var x509 = new X509Certificate2(HttpContext.Current.Server.MapPath("~/App_Data/" + ConfigurationManager.AppSettings["CertFileName"]));
// Verify the data with the signature
var csp = (RSACryptoServiceProvider)x509.PublicKey.Key;
if (!csp.VerifyData(data, "SHA256", signature))
{
// Signature verification failed; data was possibly altered
throw new SecurityTokenValidationException("Data signature verification failed. Token cannot be trusted!");
}
// strip off signature from token
token = token.Substring(0, token.LastIndexOf('.') + 1);
// Convert Base64 encoded token to Base64Url encoding
token = token.Replace('+', '-').Replace('/', '_').Replace("=", "");
// Use JwtSecurityTokenHandler to validate the JWT token
var tokenHandler = new JwtSecurityTokenHandler();
// Read the JWT
var parsedJwt = tokenHandler.ReadToken(token);
// Set the expected properties of the JWT token in the TokenValidationParameters
var validationParameters = new TokenValidationParameters()
{
NameClaimType = "http://wso2.org/claims/enduser",
AuthenticationType = ((JwtSecurityToken)parsedJwt).Claims.Where(c => c.Type == "http://wso2.org/claims/usertype").First().Value,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = false,
RequireExpirationTime = true,
RequireSignedTokens = false,
//ValidAudience = ConfigurationManager.AppSettings["AllowedAudience"],
ValidIssuer = ConfigurationManager.AppSettings["Issuer"],
//IssuerSigningToken = new X509SecurityToken(cert),
CertificateValidator = X509CertificateValidator.None
};
// Set both HTTP Context and Thread principals, so they will be in sync
HttpContext.Current.User = tokenHandler.ValidateToken(token, validationParameters, out parsedJwt);
Thread.CurrentPrincipal = HttpContext.Current.User;
// Treat as ClaimsPrincipal, extract JWT expiration and inject it into request headers
var cp = (ClaimsPrincipal)Thread.CurrentPrincipal;
context.Request.Headers.Add("JWT-Expiration", cp.FindFirst("exp").Value);
}
catch (SecurityTokenValidationException stvErr)
{
// Log error
if (context.Trace.IsEnabled)
context.Trace.Write("JwtAuthorization", "Error validating token.", stvErr);
}
catch (System.Exception ex)
{
// Log error
if (context.Trace.IsEnabled)
context.Trace.Write("JwtAuthorization", "Error parsing token.", ex);
}
答案 1 :(得分:0)
WSO2提供了一个选项,可以将JWT的格式更改为URL编码,此后将不需要自定义代码。
文档@ https://docs.wso2.com/display/AM260/Passing+Enduser+Attributes+to+the+Backend+Using+JWT提到:
“但是,对于某些应用,您可能需要使用Base64URL编码。要使用Base64URL编码对JWT进行编码,请在/repository/conf/api-manager.xml中的元素中添加URLSafeJWTGenerator类”