我遇到一些麻烦手动验证由Identity Server 4发出的JWT令牌。使用
ClientId:“CLIENT1” ClientSecret:“123456”
我一直得到的例外是:IDX10501:签名验证失败。无法匹配键:'[PII默认隐藏。将IdentityModelEventSource.cs中的'ShowPII'标志设置为true以显示它。]'
有人能告诉我哪里出错了。
private static void ValidateJwt(string jwt, DiscoveryResponse disco)
{
var parameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidIssuer = disco.Issuer,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("123456")),
ValidAudience = "CLIENT1",
//IssuerSigningKeys = keys,
// ValidateAudience = true,
// ValidateLifetime = true,
};
SecurityToken validatedToken;
var handler = new JwtSecurityTokenHandler();
handler.InboundClaimTypeMap.Clear();
try
{
var user = handler.ValidateToken(jwt, parameters, out validatedToken);
}
catch(Exception ex)
{
var error = ex.Message;
}
}
答案 0 :(得分:5)
在此示例中查看ValidateJwt()
:
您缺少的位是从发现文档加载公钥。
答案 1 :(得分:5)
尝试更改私钥的长度。我想您的私钥太小,无法编码。
答案 2 :(得分:1)
IdentityServer使用RS256签署JWT。这意味着您需要使用公钥来验证JWT(您可以从发现文档中获取此信息)。
客户ID&客户端密钥是用于请求令牌的客户端凭据。他们没有参与验证它们。
答案 3 :(得分:1)
您正在尝试使用SymmetricKey进行JWT验证。尝试在JWT.io中查找您的令牌,如果算法是“RS256”,那么SymmetricKey将无效。
答案 4 :(得分:1)
对于手动验证,您可以使用
static byte[] FromBase64Url(string base64Url)
{
string padded = base64Url.Length % 4 == 0
? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
string base64 = padded.Replace("_", "/")
.Replace("-", "+");
return Convert.FromBase64String(base64);
}
这也回答了@ henk-holterman的问题
Encoding.UTF8.GetBytes(不可能是正确的方法。
尽管实际上,更好的方法是通过OIDC发现端点 Auth0使用标准的NuGet软件包对此进行了很好的介绍。基本上,您将从发现端点加载所需的一切。
IConfigurationManager<OpenIdConnectConfiguration> configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>($"{auth0Domain}.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever());
OpenIdConnectConfiguration openIdConfig = await configurationManager.GetConfigurationAsync(CancellationToken.None);
TokenValidationParameters validationParameters =
new TokenValidationParameters
{
ValidIssuer = auth0Domain,
ValidAudiences = new[] { auth0Audience },
IssuerSigningKeys = openIdConfig.SigningKeys
};
SecurityToken validatedToken;
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
var user = handler.ValidateToken("eyJhbGciOi.....", validationParameters, out validatedToken);
就我而言,我没有发现端点。只是一个JWKS端点。 所以我选择这样做。
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using RestSharp;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Threading.Tasks;
public class ExpectedJwksResponse
{
[JsonProperty(PropertyName = "keys")]
public List<JsonWebKey> Keys { get; set; }
}
private static async Task<List<SecurityKey>> GetSecurityKeysAsync()
{
// Feel free to use HttpClient or whatever you want to call the endpoint.
var client = new RestClient("<https://sample-jwks-endpoint.url>");
var request = new RestRequest(Method.GET);
var result = await client.ExecuteTaskAsync<ExpectedJwksResponse>(request);
if (result.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception("Wasnt 200 status code");
}
if (result.Data == null || result.Data.Keys == null || result.Data.Keys.Count == 0 )
{
throw new Exception("Couldnt parse any keys");
}
var keys = new List<SecurityKey>();
foreach ( var key in result.Data.Keys )
{
keys.Add(key);
}
return keys;
}
private async Task<bool> ValidateToken(token){
TokenValidationParameters validationParameters = new TokenValidationParameters
{
RequireExpirationTime = true,
RequireSignedTokens = true,
ValidateLifetime = true,
ValidIssuer = "https://sample-issuer.com",
ValidAudiences = new[] { "https://sample-audience/resource" },
IssuerSigningKeys = await GetSecurityKeysAsync()
};
var user = null as System.Security.Claims.ClaimsPrincipal;
SecurityToken validatedToken;
try
{
user = handler.ValidateToken(token, validationParameters, out validatedToken);
}
catch ( Exception e )
{
Console.Write($"ErrorMessage: {e.Message}");
return false;
}
var readToken = handler.ReadJwtToken(token);
var claims = readToken.Claims;
return true;
}
答案 5 :(得分:0)
您已指定:
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret"))
但JwtSecurityTokenHandler
无法与can be part of jwt header itself的密钥匹配。基本上,这意味着您的配置与真实发行者的配置不匹配[es]。该错误表明这与签名密钥有关。
请检查该发行人的配置(如果可以),找出遗漏的部分,然后重试。
您可以使用jwt.io在线调试您的jwt。
答案 6 :(得分:0)
请在创建JWT令牌时检查并确保添加了SigningCredentials。
10 * 24 * 60 * 60 * 1000