2015-10-19 84 views
0

有人可以提供示例C#.NET代碼來驗證由WSO2 API網關發佈的使用SHA256withRSA算法簽名的JWT。我很確定我需要設置TokenValidationParameters.IssuerSigningToken,然後調用JwtSecurityTokenHandler.ValidateToken方法,但是我一直無法使它工作,或找到任何示例代碼。使用SHA256withRSA算法驗證WSO2 API網關JWT簽名的C#.NET代碼

這是我到目前爲止有:

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

回答

2

的智威湯遜從WSO2 API網關不符合規範(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); 
}