簡體   English   中英

在 C# 中手動驗證 JWT 令牌

[英]Manually validating a JWT token in C#

我在手動驗證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;
        }

    }

在此示例中查看ValidateJwt()

https://github.com/IdentityServer/IdentityServer4/blob/master/samples/Clients/old/MvcManual/Controllers/HomeController.cs

您缺少的一點是從發現文檔中加載公鑰。

嘗試更改私鑰的長度。 我想您的私鑰太小而無法編碼。

對於手動驗證,您可以使用

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

你可以在這里閱讀更多關於它的信息或者他們的 GitHub 示例頁面在這里

就我而言,我沒有發現端點。 只是一個 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;
}

您已指定:

IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret"))

但是JwtSecurityTokenHandler無法將它與可以是 jwt 標頭本身的一部分的密鑰相匹配。 基本上這意味着您的配置與實際發行人的配置不匹配[es]。 該錯誤表明這與簽名密鑰有關。

請檢查該發行者的配置(如果可以),找出遺漏的部分,然后重試。

您可以使用jwt.io在線調試您的 jwt。

IdentityServer 使用 RS256 對 JWT 進行簽名。 這意味着您需要使用公鑰來驗證 JWT(您可以從發現文檔中獲取)。

客戶端 ID 和客戶端密碼是用於請求令牌的客戶端憑據。 他們沒有參與驗證它們。

您正在嘗試使用 SymmetricKey 進行 JWT 驗證。 嘗試在JWT.io 中查看您的令牌,如果算法是“RS256”,則 SymmetricKey 將不起作用。

請在創建 JWT 令牌時檢查確保您添加了 SigningCredentials。

var token = new JwtSecurityToken(
  Constants.Audiance,Constants.Issuer,claims
   notBefore:DateTime.Now,
   expires:DateTime.Now.AddHours(1),
   **signinCredential**
   );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM