为什么我会得到SecurityTokenSignatureKeyNotFoundException

本文关键字:SecurityTokenSignatureKeyNotFoundException 为什么 | 更新日期: 2023-09-27 17:56:16

当我尝试将此JWT(由Azure Mobile Services颁发)作为HTTP标头/授权/持有者令牌传递时:

Header:
{
    "alg": "HS256", 
    "typ": "JWT", 
    "kid": "0"
}
Claims:
{
    "ver": 2, 
    "aud": "Facebook", 
    "iss": "urn:microsoft:windows-azure:zumo", 
    "urn:microsoft:credentials": "pYK8b5...", 
    "exp": 1436730730, 
    "uid": "Facebook:10000xxxxxxxxxx"
}

进入我的 ASP.NET WEB API 配置:

const string issuer = "urn:microsoft:windows-azure:zumo";
byte[] mobileServicesSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:SecretKey"]);
app.UseJwtBearerAuthentication(
    new JwtBearerAuthenticationOptions
    {
      AuthenticationMode = AuthenticationMode.Active,
      AllowedAudiences = new[] { "Facebook" },
      IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
              {
                  new SymmetricKeyIssuerSecurityTokenProvider(issuer,  mobileServicesSecret)
              }
    });

我得到:

类型的第一次机会异常 'System.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException' 发生在System.IdentityModel.Tokens.Jwt中.dll

我怀疑这是因为"孩子"财产的存在?

编辑:使用此 https://github.com/Magenic/JWTvalidator/tree/master/JwtValidator/JwtValidator,可以验证JWT,因此没有错。但我真的很想使用OWIN/Katana。

为什么我会得到SecurityTokenSignatureKeyNotFoundException

谷歌建议如下:调用令牌信息终结点

我们强烈建议您不要编写自己的代码来执行这些验证步骤,而是使用适用于您的平台的 Google API 客户端库,或调用我们的 tokeninfo 验证端点。

要使用 tokeninfo 终结点验证 ID 令牌,请向终结点发出 HTTPS POST 或 GET 请求,并在 id_token 参数中传递 ID 令牌。例如,若要验证令牌"XYZ123",请发出以下 GET 请求:

自定义 JwtHandler.cs

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens;
using System.Linq;
using System.Net.Http;
using System.Web;
using System.Web.Configuration;
using Newtonsoft.Json;
using System.Net;
using System.Threading.Tasks;
using System.Threading;
using Services.Models;
using System.Security.Claims;
namespace Services
{
    /// <summary>
    ///  This is an implementation of Google JWT verification that
    ///  demonstrates:
    ///    - JWT validation
    /// </summary>
    /// @author kunal.bajpai@gmail.com (Kunal Bajpai)

    public class CustomJwtHandler : DelegatingHandler
    {
        private const string URL_GOOGLE_TOKEN_INFO = "https://www.googleapis.com/oauth2/v3/tokeninfo";
        /// <summary>
        /// 
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            HttpStatusCode statusCode;
            string token;
            var authHeader = request.Headers.Authorization;
            if (authHeader == null)
            {
                // Missing authorization header
                return base.SendAsync(request, cancellationToken);
            }
            if (!TryRetrieveToken(request, out token))
            {
                return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(HttpStatusCode.Unauthorized));
            }
            try
            {
                ValidateToken(token);
                return base.SendAsync(request, cancellationToken);
            }
            catch (SecurityTokenInvalidAudienceException)
            {
                statusCode = HttpStatusCode.Unauthorized;
            }
            catch (SecurityTokenValidationException)
            {
                statusCode = HttpStatusCode.Unauthorized;
            }
            catch (Exception)
            {
                statusCode = HttpStatusCode.InternalServerError;
            }
            return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode));
        }
        /// <summary>
        /// Validates JWT Token
        /// </summary>
        /// <param name="JwtToken"></param>
        private void ValidateToken(string JwtToken)
        {
            try
            {
                using (WebClient wc = new WebClient())
                {
                    TokenInfo tokenInfo = JsonConvert.DeserializeObject<TokenInfo>(wc.DownloadString(URL_GOOGLE_TOKEN_INFO + "?id_token=" + JwtToken));
                    ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(ExtractClaims(tokenInfo), tokenInfo.Issuer));
                    Thread.CurrentPrincipal = claimsPrincipal;
                    HttpContext.Current.User = claimsPrincipal;
                }
            }
            catch (WebException e)
            {
                HttpStatusCode statusCode = ((HttpWebResponse)e.Response).StatusCode;
                if (statusCode == HttpStatusCode.BadRequest)
                {
                    throw new SecurityTokenValidationException();
                }
                else
                {
                    throw new Exception();
                }
            }
        }
        /// <summary>
        /// Tries to retrieve Token
        /// </summary>
        /// <param name="request"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
        {
            token = null;
            IEnumerable<string> authorizationHeaders;
            if (!request.Headers.TryGetValues("Authorization", out authorizationHeaders) ||
            authorizationHeaders.Count() > 1)
            {
                return false;
            }
            var bearerToken = authorizationHeaders.ElementAt(0);
            token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
            return true;
        }
        private List<Claim> ExtractClaims(TokenInfo tokenInfo)
        {
            List<Claim> claims = new List<Claim> {
                new Claim(ClaimTypes.Name, tokenInfo.Name),
                new Claim(ClaimTypes.Email, tokenInfo.Email),
                new Claim(ClaimTypes.GivenName, tokenInfo.GivenName),
                new Claim(ClaimTypes.Surname, tokenInfo.FamilyName),
                new Claim(ApplicationUser.CLAIM_TYPE_LOCALE, tokenInfo.Locale),
                new Claim(ClaimTypes.NameIdentifier, tokenInfo.ProviderKey, ClaimValueTypes.String, tokenInfo.Issuer),
                new Claim(ApplicationUser.CLAIM_TYPE_EMAIL_CONFIRMED, tokenInfo.IsEmailVerifed.ToString(), ClaimValueTypes.Boolean)
            };
            return claims;
        }
    }
}

令牌信息.cs

using Microsoft.AspNet.Identity.EntityFramework;
using Newtonsoft.Json;
namespace Services.Models
{
    public class TokenInfo
    {
        [JsonProperty("iss")]
        public string Issuer { get; set; }
        [JsonProperty("aud")]
        public string AudienceClientId { get; set; }
        [JsonProperty("sub")]
        public string ProviderKey { get; set; }
        [JsonProperty("email_verified")]
        public bool IsEmailVerifed { get; set; }
        [JsonProperty("azp")]
        public string AndroidClientId { get; set; }
        [JsonProperty("email")]
        public string Email { get; set; }
        [JsonProperty("iat")]
        public long IssuedAt { get; set; }
        [JsonProperty("exp")]
        public long ExpiresAt { get; set; }
        [JsonProperty("name")]
        public string Name { get; set; }
        [JsonProperty("picture")]
        public string Picture { get; set; }
        [JsonProperty("given_name")]
        public string GivenName { get; set; }
        [JsonProperty("family_name")]
        public string FamilyName { get; set; }
        [JsonProperty("locale")]
        public string Locale { get; set; }
        [JsonProperty("alg")]
        public string Algorithm { get; set; }
        [JsonProperty("kid")]
        public string kid { get; set; }
        public override bool Equals(object obj)
        {
            if (obj.GetType() != typeof(ApplicationUser))
            {
                return false;
            }
            ApplicationUser user = (ApplicationUser)obj;
            bool hasLogin = false;
            foreach (IdentityUserLogin login in user.Logins)
            {
                if (login.ProviderKey == ProviderKey)
                {
                    hasLogin = true;
                    break;
                }
            }
            if (!hasLogin) { return false; }
            if (user.FirstName != GivenName) { return false; }
            if (user.LastName != FamilyName) { return false; }
            if (user.Locale != Locale) { return false; }
            return base.Equals(obj);
        }
    }
}

WebApiConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using Microsoft.Owin.Security.OAuth;
using Newtonsoft.Json.Serialization;
namespace Services
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            // Configure Web API to use only bearer token authentication.
            config.SuppressDefaultHostAuthentication();
            config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
            // Web API routes
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
            config.MessageHandlers.Add(new CustomJwtHandler());
        }
    }
}
相关文章:
  • 没有找到相关文章