2015-06-13 5 views
7

Когда я пытаюсь передать этот JWT (выданный Azure Mobile Services) в качестве заголовка HTTP/авторизацию/Bearer маркер:Почему я получаю SecurityTokenSignatureKeyNotFoundException?

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

I получить:

Первый шанс исключение типа 'System.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException' произошло в Syst em.IdentityModel.Tokens.Jwt.dll

Я подозреваю, что это связано с наличием свойства «ребенок»?

РЕДАКТИРОВАТЬ: Используя это https://github.com/Magenic/JWTvalidator/tree/master/JwtValidator/JwtValidator, можно проверить JWT, так что в этом нет ничего плохого. Но я действительно хочу использовать OWIN/Katana.

+0

Не могли бы вы решить проблему? Я застрял в этом. Не могли бы вы предоставить код. –

+0

@KunalB. нет, извините, я так и не нашел решение использовать Owin/Katana. Я должен был использовать класс JwtValidator в ссылке и использовать собственный атрибут аутентификации для его проверки. Microsoft делает то, что они делают лучше всего; одна команда (команда Azure Mobiles Services) сидит на одной стороне забора, другая (команда ASP.NET) сидит с другой стороны, и они, вероятно, никогда не разговаривали друг с другом ... :( –

+0

Через 2 дня вот что Я нашел - http://markwalsh.io/development/2014/12/02/ASP.Net%20Web%20API%20with%20JWT/ это сработало для меня. Во время отладки у меня все еще появляется какое-то странное сообщение. –

ответ

0

Google предлагает следующие - Calling the tokeninfo endpoint

Вместо того, чтобы писать свой собственный код для выполнения этих этапов проверки, мы настоятельно рекомендуем использовать API клиентской библиотеки Google для вашей платформы, или позвонив проверки tokeninfo конечной точки ,

Чтобы проверить токен ID, используя конечную точку tokeninfo, сделайте запрос HTTPS POST или GET конечной точке и передайте токен ID в параметре id_token. Например, для проверки маркера "XYZ123", сделать следующий запрос GET:

CustomJwtHandler.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 [email protected] (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; 
     } 
    } 
} 

TokenInfo.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()); 
     } 
    } 
} 
+0

Что вы думаете если мы часто вызываем службу Google, чтобы проверить токен? – Redplane

+0

Ничего не случится. Вероятно, вы потеряете квоту. –

+0

Вот почему я думаю о проверке Google Token на сервере, который я реализую – Redplane