2016-12-01 152 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