2017-09-20 34 views
5

(編輯 - 找到合適的修復見下文!)使用JWT對.NET核心Web 2.0的API - 添加身份打破了智威湯遜認證

OK - 這是我對.NET核心2.0和認證的第一次嘗試,雖然過去我已經使用Web API 2.0完成了一些工作,並且在過去的幾年中已經廣泛應用於各種MVC和Webforms ASP項目。

我想創建一個使用.Net核心的Web API ONLY項目。這將形成多租戶應用程序的後端,用於生成一些報告,因此我需要能夠對用戶進行身份驗證。似乎通常的做法是使用JWT - 首先驗證用戶生成令牌,然後將其傳遞給客戶端以在每個API請求上使用。數據將使用EF Core進行存儲和檢索。

我跟着this post一個基本的方式來獲得這種設置,我設法得到這個確定的工作 - 我有一個接受一個用戶名/密碼,如果有效,則返回令牌的控制器,以及一些授權策略設置基於索賠。

我需要的下一件事是實際管理用戶/密碼/等。我認爲我只是使用.Net Core Identity來做這件事,因爲我會有很多現成的代碼來擔心用戶/角色,密碼等。我使用的是自定義User類和UserRole類,這些類來自標準IdentityUserIdentityRole類,但現在我已經恢復到標準類。

我的問題是,我不能完全弄清楚如何添加身份&註冊所有的各種服務(rolemanager,的UserManager等),也沒有打破認證 - 基本上,只要我這行添加到我的Startup.ConfigureServices類:

services.AddIdentity<IdentityUser, IdentityRole>() 
    .AddEntityFrameworkStores<MyContext>(); 

這一切都錯了,我再也看不到任何索賠時,我收到一個請求,讓所有的政策只是鎖定,你不能得到任何東西。

如果我沒有這些行,那麼我最終會遇到與UserManager,RoleManager,UserStore等相關的錯誤,而這些錯誤都不會被註冊爲DI。

所以...如何(如果可能的話)我可以註冊身份並正確地將其掛接到上下文,但避免/刪除對實際授權機制的任何更改?

我在網上瀏覽過一些公平的文章,但是自從.Net Core 1.x發佈以來,很多教程等都不再真正有效。

我不打算讓這個API應用程序有任何前端代碼,所以我現在不需要任何cookie身份驗證。

編輯
OK,現在我發現,在該代碼設置了智威湯遜認證的Startup.ConfigureServices()方法:

services.AddAuthentication(
      JwtBearerDefaults.AuthenticationScheme) 
       .AddJwtBearer(options => 
       { 
       >>breakpoint>>> options.TokenValidationParameters = 
         new TokenValidationParameters 
         { 
          ValidateIssuer = true, 
          ValidateAudience = true, 
          ValidateLifetime = true, 
          ValidateIssuerSigningKey = true, 

          ValidIssuer = "Blah.Blah.Bearer", 
          ValidAudience = "Blah.Blah.Bearer", 
          IssuerSigningKey = 
          JwtSecurityKey.Create("verylongsecretkey") 

         }; 
       }); 

如果我把在指定線路斷點(通過「> >斷點>>>「)然後它會得到打當我不要添加行來添加身份證服務,但如果我確實添加這些行然後它從來沒有被擊中。無論我在services.AddIdentity()調用中的方法在哪裏,都是如此。我知道這只是一個lambda表達式,所以它會在稍後執行,但是有什麼辦法可以讓AddIdentity的東西不設置Authentication,或者讓代碼立即刪除它?我在某些時候假設有一些代碼,選擇不進行配置我已經設置有作爲身份的東西已經設置運行LAMBDA ...

感謝您閱讀所有,如果您有:)

編輯 - 找到了答案
好吧,我終於發現了這個問題,GH這基本上正是這個問題: https://github.com/aspnet/Identity/issues/1376

基本上我不得不這樣做是雙重的:

ENS URE在調用services.AddIdentity<IdentityUser, IdentityContext()作出第一

改變呼叫添加AUTH來自:

services.AddAuthentication(
      JwtBearerDefaults.AuthenticationScheme) 
       .AddJwtBearer(options => 
... 

要:

services.AddAuthentication(options => 
     { 
      options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 
      options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 
     }) 
      .AddJwtBearer(options => 
... 

這並不惱人導致一個cookie被創建,但這不是那麼用於身份驗證,據我可以告訴 - 這純粹是利用上的請求承載令牌控制器,其中至少有[Authorize(Policy = "Administrator")]或類似的一組/動作。

我需要測試更多的,我會盡量回來這裏的更新,如果我發現它不以某種方式工作。

(編輯 - 把妥善解決在像現在一樣的答案)

+0

你救了我。謝謝 –

+0

你應該考慮把這個問題分解成一個問題,然後自己回答它作爲正確的答案。 – alwayslearning

+0

@alwayslearning不是一個壞主意......所以我這樣做了。 – GPW

回答

3

我終於拼湊的解決方案,讓用戶alwayslearning的建議,我已經編輯我的職務,我把這個作爲一個實際的回答。

OK,這可以做好。首先,您需要使用我在上面編輯中指出的身份驗證選項 - 沒關係。 然後,你需要使用services.AddIdentityCore<TUser>()而非services.AddIdentity<TUser>()。然而,這並沒有爲角色管理添加一大堆東西,而且顯然缺乏適當的構造函數來給它使用你想使用的角色類型。這意味着,在我的情況下,我不得不這樣做:

IdentityBuilder builder = services.AddIdentityCore<IdentityUser>(opt => 
     { 
      opt.Password.RequireDigit = true; 
      opt.Password.RequiredLength = 8; 
      opt.Password.RequireNonAlphanumeric = false; 
      opt.Password.RequireUppercase = true; 
      opt.Password.RequireLowercase = true; 
     } 
     ); 
     builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services); 
     builder 
      .AddEntityFrameworkStores<MyContext>(); 
     //.AddDefaultTokenProviders(); 

     builder.AddRoleValidator<RoleValidator<IdentityRole>>(); 
     builder.AddRoleManager<RoleManager<IdentityRole>>(); 
     builder.AddSignInManager<SignInManager<IdentityUser>>(); 

已經這樣做了,接下來的事情就是確保驗證用戶登錄時(在發送之前令牌),你一定要使用SignInManager方法CheckPasswordSignInAsyncPasswordSignInAsync

public async Task<IdentityUser> GetUserForLogin(string userName, string password) 
    { 
     //find user first... 
     var user = await _userManager.FindByNameAsync(userName); 

     if (user == null) 
     { 
      return null; 
     } 

     //validate password... 
     var signInResult = await _signInManager.CheckPasswordSignInAsync(user, password, false); 

     //if password was ok, return this user. 
     if (signInResult.Succeeded) 
     { 
      return user; 
     } 

     return null; 
    } 

如果使用PasswordSignInAsync方法,那麼你會得到一個運行時錯誤重。沒有配置IAuthenticationSignInHandler。

我希望這可以幫助別人在某些時候。

+0

你絕對幫了我。非常感謝。 當你沒有JWT或Identity的經驗時,互聯網上有很多教程過時,很難找到解決方案。 –