2015-04-07 55 views
1

我已經按照教程,直到this point在系列。我在解決方案中使用了一個項目,既充當令牌發行機構,又充當資源服務器。Owin with JWT的Web Api總是無法授權請求

JWT是使用啓動類中提到的端點生成的,我也在jwt.io上進行了驗證。然而,當我通過使用郵遞員Chrome瀏覽器與授權屬性所獲取的資源API結束點這智威湯遜,我總是覺得它返回

{ 「消息」:「授權已被拒絕了這個請求」 }

下面的api控制器類中的其他api方法在Chrome上通過Postman調用時起作用。

我用從的NuGet控制檯啓動類

public void Configuration(IAppBuilder app) 
    { 
     HttpConfiguration config = new HttpConfiguration(); 
     ConfigureOAuthTokenGeneration(app); 
     ConfigureOAuthTokenConsumption(app); 
     WebApiConfig.Register(config); 
     app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); 
     app.UseWebApi(config); 
    } 


    private void ConfigureOAuthTokenGeneration(IAppBuilder app) 
    { 
     OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() 
     { 
      //For Dev enviroment only (on production should be AllowInsecureHttp = false) 
      AllowInsecureHttp = true, 
      TokenEndpointPath = new PathString("/oauth/token"), 
      AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), 
      Provider = new CustomOAuthProvider(), 
      AccessTokenFormat = new CustomJwtFormat(ConfigurationManager.AppSettings["Issuer"]), 
     }; 

     // OAuth 2.0 Bearer Access Token Generation 
     app.UseOAuthAuthorizationServer(OAuthServerOptions); 
    } 

    private void ConfigureOAuthTokenConsumption(IAppBuilder app) 
    { 
     string issuer = ConfigurationManager.AppSettings["Issuer"]; 
     string audienceId = ConfigurationManager.AppSettings["AudienceId"]; 
     byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["AudienceSecret"]); 

     // Api controllers with an [Authorize] attribute will be validated with JWT 
     app.UseJwtBearerAuthentication(
      new JwtBearerAuthenticationOptions 
      { 
       AuthenticationMode = AuthenticationMode.Active, 
       AllowedAudiences = new[] { audienceId }, 
       IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[] 
       { 
        new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret) 
       } 
      }); 
    } 

代碼在自定義OAuthProvider

public class CustomOAuthProvider : OAuthAuthorizationServerProvider 
    { 
     public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) 
     { 
      context.Validated(); 
      return Task.FromResult<object>(null); 
     } 

     public override Task MatchEndpoint(OAuthMatchEndpointContext context) 
     { 
      //avoid pre-flight calls 
      if (context.OwinContext.Request.Method == "OPTIONS" && context.IsTokenEndpoint) 
      { 
       context.OwinContext.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "POST" }); 
       context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "accept", "authorization", "content-type" }); 
       context.OwinContext.Response.StatusCode = 200; 
       context.RequestCompleted(); 

       return Task.FromResult<object>(null); 
      } 

      return base.MatchEndpoint(context);  
     } 

     public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
     { 
      context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); 

      //setting up claims in the constructor of class UserDetails 
      UserDetails user = new UserDetails(); 
      user.UserName = context.UserName; 
      user.FirstName = "Dummy First"; 
      user.LastName = "Dummy Last"; 

      ClaimsIdentity identity = new ClaimsIdentity("JWT-BearerAuth-Test"); 
      identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName)); 
      foreach (string claim in user.Claims) 
      { 
       identity.AddClaim(new Claim(ClaimTypes.Role, claim));  
      } 
      var ticket = new AuthenticationTicket(identity, null); 

      context.Validated(ticket); 

     } 
    } 

需要

代碼的所有DLL的最新版本定製JWT類

public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket> 
    { 
     private readonly string _issuer = string.Empty; 

     public CustomJwtFormat(string issuer) 
     { 
      _issuer = issuer; 
     } 

     public string Protect(AuthenticationTicket data) 
     { 
      if (data == null) 
      { 
       throw new ArgumentNullException("data"); 
      } 

      string audienceId = ConfigurationManager.AppSettings["AudienceId"]; 

      string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["AudienceSecret"]; 

      var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64); 

      var signingKey = new HmacSigningCredentials(keyByteArray); 
      var issued = data.Properties.IssuedUtc; 
      var expires = data.Properties.ExpiresUtc; 
      var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey); 
      var handler = new JwtSecurityTokenHandler(); 
      var jwt = handler.WriteToken(token); 
      return jwt; 
     } 

    } 

資源服務器的API控制器

public class AdminController : ApiController 
    { 
     //This call works 
     public IHttpActionResult ReadData(string id) 
     { 
      return Ok("ID sent in:" + id); 
     } 

     //[Authorize(Roles="EditRecord")] //doesnt work 
     [Authorize] //doesnt work either 
     public IHttpActionResult EditData(string id) 
     { 
      return Ok("Edited ID:" + id); 
     } 
    } 

我的環境是VS2013與框架4.5中使用OAuth2和網絡API 2.請原諒的長期職位。

+0

嗨,你能得到這個工作?我面臨同樣的問題。正在搜索但找不到任何解決方案 –

回答

0

您需要確保方法「ConfigureOAuthTokenConsumption」中使用的issuer,audienceId和audienceSecret的值與生成JWT令牌時使用的值相同,請注意尾部的斜線「/」。

這是我現在唯一想到的。

+0

它與web.config文件中的值相同,並從此處自行取出。對於令牌創建和消費都只有一個項目,所以即使錯誤,值也不會有差異 – user20358