2015-06-13 13 views
7

Quando provo a passare questo JWT (rilasciato da Azure Mobile Services) come un'intestazione HTTP/autorizzazione/portatore token:Perché ottengo 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" 
} 

Nel mio ASP.NET WEB API configurata:

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 get:

Una prima eccezione di possibilità di tipo 'System.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException' si è verificato in Syst em.IdentityModel.Tokens.Jwt.dll

Ho il sospetto che questo è perché la presenza della proprietà "ragazzo"?

MODIFICA: utilizzando questo https://github.com/Magenic/JWTvalidator/tree/master/JwtValidator/JwtValidator, è possibile convalidare il JWT, quindi non c'è niente di sbagliato in esso. Ma voglio davvero usare OWIN/Katana.

+0

Potresti superare il problema? Sono bloccato con questo. Potrebbe fornire il codice. –

+0

@ KunalB. no, scusate, non ho mai trovato una soluzione per usare Owin/Katana. Ho dovuto utilizzare la classe JwtValidator nel link e utilizzare un attributo di autenticazione personalizzato per convalidarlo. Microsoft fa ciò che sa fare meglio; un team (il team Azure Mobiles Services) siede su un lato del recinto, l'altro (il team ASP.NET) si trova dall'altra parte, e probabilmente non si sono mai parlati ... :( –

+0

Dopo 2 giorni ecco cosa Ho trovato - http://markwalsh.io/development/2014/12/02/ASP.Net%20Web%20API%20with%20JWT/ questo ha funzionato per me. Durante il debug ho ancora un messaggio strano –

risposta

0

Google suggerisce la seguente - Calling the tokeninfo endpoint

Piuttosto che scrivere il proprio codice per eseguire questa procedura di verifica, si consiglia vivamente di utilizzare una libreria client API di Google per la propria piattaforma, o chiamando il nostro endpoint convalida tokeninfo .

Per convalidare un token ID utilizzando l'endpoint tokeninfo, effettuare una richiesta HTTPS POST o GET all'endpoint e passare il token ID nel parametro id_token. Ad esempio, per validare il token "XYZ123", rendono la seguente richiesta 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

Cosa ne pensi? se chiamiamo il servizio Google così frequentemente per convalidare il token? – Redplane

+0

Non succederebbe nulla. Probabilmente la quota verrà superata –

+0

Ecco perché sto pensando di verificare il token Google sul server che implemento – Redplane

Problemi correlati