2016-12-01 154 views
0

我正在使用ASP.NET MVC核心作为后端API的Angular SPA,并且我的 让我的JWT身份验证正常工作时遇到了很多麻烦。JWT使用Angular和MVC Core进行身份验证/授权

我使用Openiddict作为我的JWT中间件来发放令牌。我可以成功向我的控制器发送令牌请求,将用户登录并将令牌发送回客户端。

但是,当我尝试访问受保护的API路由时,我收到401未经授权的消息。我可以看到这个令牌是在请求的头部发送的,所以它不能在服务器端正确读取,所以我认为这只是一个配置问题。我所看到的每个资源都使得看起来没有其他配置明智的做法。

这里是代码的相关部分:

启动配置服务

public void ConfigureServices(IServiceCollection services) 
    { 
     services.AddMvc(); 
     services.AddAuthorization(); 

     services.AddEntityFramework() 
      .AddEntityFrameworkSqlServer() 
      .AddDbContext<DbContext>(); 

     services.AddIdentity<User, IdentityRole>(config => 
     { 
      config.User.RequireUniqueEmail = true; 
      config.Password.RequiredLength = 8; 
     }) 
     .AddEntityFrameworkStores<DbContext>() 
     .AddDefaultTokenProviders(); 

     services.AddOpenIddict<DbContext>() 
      .AddMvcBinders() 
      .EnableTokenEndpoint("/auth/token") 
      .UseJsonWebTokens() 
      .AllowPasswordFlow() 
      .AddEphemeralSigningKey() 
      //.AddSigningCertificate() 
      .DisableHttpsRequirement(); 

     services.AddLogging(); 
    } 

启动配置应用

public void Configure(IApplicationBuilder app, RequestJockeyDataSeeder seeder, ILoggerFactory factory) 
    { 

     app.UseDefaultFiles(new DefaultFilesOptions() 
     { 
      DefaultFileNames = new[] { "index.html" } 
     }); 
     app.UseStaticFiles(); 

     app.UseOpenIddict(); 

     app.UseJwtBearerAuthentication(new JwtBearerOptions() 
     { 
      AutomaticAuthenticate = true, 
      AutomaticChallenge = true, 
      Audience = "http://localhost:5000", 
      Authority = "http://localhost:5000", 
      RequireHttpsMetadata = false, 

     }); 

     app.UseMvc(); 

    } 

控制器 - 我得到这个从一个例子在网上

[HttpPost("~/auth/token"), Produces("application/json")] 
    public async Task<IActionResult> Token(OpenIdConnectRequest request) 
    { 
     if (!request.IsPasswordGrantType()) 
     { 
      // Return bad request if the request is not for password grant type 
      return BadRequest(new OpenIdConnectResponse 
      { 
       Error = OpenIdConnectConstants.Errors.UnsupportedGrantType, 
       ErrorDescription = "The specified grant type is not supported." 
      }); 
     } 

     var user = await _userManager.FindByNameAsync(request.Username); 
     if (user == null) 
     { 
      // Return bad request if the user doesn't exist 
      return BadRequest(new OpenIdConnectResponse 
      { 
       Error = OpenIdConnectConstants.Errors.InvalidGrant, 
       ErrorDescription = "Invalid username or password" 
      }); 
     } 

     // Check that the user can sign in and is not locked out. 
     // If two-factor authentication is supported, it would also be appropriate to check that 2FA is enabled for the user 
     if (!await _signInManager.CanSignInAsync(user) || (_userManager.SupportsUserLockout && await _userManager.IsLockedOutAsync(user))) 
     { 
      // Return bad request is the user can't sign in 
      return BadRequest(new OpenIdConnectResponse 
      { 
       Error = OpenIdConnectConstants.Errors.InvalidGrant, 
       ErrorDescription = "The specified user cannot sign in." 
      }); 
     } 

     if (!await _userManager.CheckPasswordAsync(user, request.Password)) 
     { 
      // Return bad request if the password is invalid 
      return BadRequest(new OpenIdConnectResponse 
      { 
       Error = OpenIdConnectConstants.Errors.InvalidGrant, 
       ErrorDescription = "Invalid username or password" 
      }); 
     } 

     // The user is now validated, so reset lockout counts, if necessary 
     if (_userManager.SupportsUserLockout) 
     { 
      await _userManager.ResetAccessFailedCountAsync(user); 
     } 

     // Create the principal 
     var principal = await _signInManager.CreateUserPrincipalAsync(user); 

     // Claims will not be associated with specific destinations by default, so we must indicate whether they should 
     // be included or not in access and identity tokens. 
     foreach (var claim in principal.Claims) 
     { 
      // For this sample, just include all claims in all token types. 
      // In reality, claims' destinations would probably differ by token type and depending on the scopes requested. 
      claim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken); 
     } 

     // Create a new authentication ticket for the user's principal 
     var ticket = new AuthenticationTicket(
      principal, 
      new AuthenticationProperties(), 
      OpenIdConnectServerDefaults.AuthenticationScheme); 

     // Include resources and scopes, as appropriate 
     var scope = new[] 
     { 
    OpenIdConnectConstants.Scopes.OpenId, 
    OpenIdConnectConstants.Scopes.Email, 
    OpenIdConnectConstants.Scopes.Profile, 
    OpenIdConnectConstants.Scopes.OfflineAccess, 
    OpenIddictConstants.Scopes.Roles 
}.Intersect(request.GetScopes()); 

     ticket.SetResources("http://localhost:5000/"); 
     ticket.SetScopes(scope); 
     ticket.Properties.ExpiresUtc = DateTimeOffset.Now.AddMinutes(15); 

     // Sign in the user 
     return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme); 
    } 

我将省略角度http拦截器,因为路由既通过应用程序也通过邮递员失败。有没有什么我错过配置MVC正确处理这些令牌?

回答

-1

启用日志记录并查看更详细的错误后已解决此问题。

我我JwtBearerAuthentication更新到这一点:

 app.UseJwtBearerAuthentication(new JwtBearerOptions() 
     { 
      AutomaticAuthenticate = true, 
      AutomaticChallenge = true, 
      Audience = "http://localhost:5000/", 
      Authority = "http://localhost:5000/", 
      RequireHttpsMetadata = false, 
      TokenValidationParameters = new TokenValidationParameters() { 
       ValidateIssuerSigningKey = false 
      } 
     } 

主要的变化是在ValidateIssuerSigningKey = False

+0

Outch不,不这样做:禁用签名密钥会允许任何人创建伪造的令牌。请用您的日志更新您的问题,这将会更容易帮助您。 – Pinpoint