2015-04-07 58 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