.NET Core Identity Cookie SignIn
至今為止我們已經了解 UserStore
與 UserManager
的使用場景,今天來學習 Identity 中驗證部份的邏輯
在上一篇的文章中有提到 SignInManager
如名稱所示,我們可以輕易猜到這個 Manager 是負責處理登入這部份的邏輯
閱讀原始碼之後發現 SignInManager
內部也有注入 UserManager
方法,代表 SignInManager
也只更高階的封裝 Github
至於該怎麼使用可以先參考 Microsoft.AspNetCore.Identity.UI
這個 Package 之前有提到裡面有預設的 Razor 頁面可以直接供我們參考 Github
此 Login 頁面中的 OnPostAsync
方法,會在我們按下 Button 後執行
- 使用
SignInManager.GetExternalAuthenticationSchemesAsync
檢查系統之中使否有設定第三方登入(Google) - 使用
SignInManager.PasswordSignInAsync
輸入帳號密碼登入 - 檢查登入回傳結果與是否有開啟二次驗證
- 轉跳回原網址
得知了 AuthenticationSchemes
這個概念,與SignInManager
不只支援一般的帳號密碼登入同時也支援第三方登入
那目前的任務就是查看微軟官方提供了多少種登入方式給我們直接使用,我們可以在 Github 上面找到
發現微軟提供了 Cookies
、JwtBearer
等常用的驗證方式,與 Google、Twitter、Facebook之類的外部登入驗證
那麼該怎麼告訴系統我們想要使用 Cookies
進行驗證呢?
先參考 Github 上的 Sample 學習一下該如何進行註冊
- 使用
AddAuthentication
方法將 Cookie AuthenticationScheme 註冊到 Services 之中 - 使用
AddCookie
方法設定 Cookie 的過期時間與更新規則 - 使用
UseAuthentication
方法指定流程需要使用 AuthenticationMiddleware
學習後回到我們自己創的專案上手動註冊看看
builder.Services
.AddAuthentication()
.AddCookie(IdentityConstants.ApplicationScheme,options =>
{
options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
});
builder.Services.AddIdentityCore<IdentityUser>()
.AddUserStore<CustomUserStore>()
.AddSignInManager<SignInManager<IdentityUser>>();
app.UseAuthentication();
在 AccountController
添加新方法
[HttpPost(template: "~/signin", Name = "SignIn")]
public async Task<SignInResult> SignIn(string userName, string password)
{
return await _signInManager.PasswordSignInAsync(
userName,
password,
false,
false);
}
在測試之前需要在我們的 CustomUserStore
實現 IUserPasswordStore
界面,使用 EFCore 可以跳過這步驟
public Task SetPasswordHashAsync(IdentityUser user, string? passwordHash, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (user == null)
{
throw new ArgumentNullException(nameof(user), $"Parameter {nameof(user)} cannot be null.");
}
if (passwordHash == null)
{
throw new ArgumentNullException(nameof(passwordHash), $"Parameter {nameof(passwordHash)} cannot be null.");
}
user.PasswordHash = passwordHash;
return Task.CompletedTask;
}
public Task<string?> GetPasswordHashAsync(IdentityUser user, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (user == null)
{
throw new ArgumentNullException(nameof(user), $"Parameter {nameof(user)} cannot be null.");
}
return Task.FromResult(user.PasswordHash);
}
public Task<bool> HasPasswordAsync(IdentityUser user, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (user == null)
{
throw new ArgumentNullException(nameof(user), $"Parameter {nameof(user)} cannot be null.");
}
return Task.FromResult(!string.IsNullOrEmpty(user.PasswordHash));
}
新增完 CustomStore 之後需要重新建立 User,因為我們之前並沒有實現 IUserPasswordStore
界面,所以 User 並沒有密碼
[HttpPost(Name = "CreateUser")]
public async Task<IdentityResult> CreateUser()
{
var userName = "User1";
var identityUser = new IdentityUser(userName);
return await _userManager.CreateAsync(identityUser, "1q2w3E*");
}
之後查詢 User 會發現 passwordHash
會自動對密碼加密
Response body
{
"id": "d319d7eb-140a-4958-bb0a-cd619b400942",
"userName": "User1",
"normalizedUserName": "USER1",
"email": null,
"normalizedEmail": null,
"emailConfirmed": false,
"passwordHash": "AQAAAAIAAYagAAAAEKEMP1C8dEb0bw19IUkDjNDnLB3ZhE2ByhWIrLIDV1RraByQ+JPRG0+nrhNiVCCPzg==",
"securityStamp": "0a442f54-5f5f-48df-8a3b-9da39621a565",
"concurrencyStamp": "0929275f-0180-44f9-9946-6a104e44d90c",
"phoneNumber": null,
"phoneNumberConfirmed": false,
"twoFactorEnabled": false,
"lockoutEnd": null,
"lockoutEnabled": false,
"accessFailedCount": 0
}
完成之後使用我們新的 API 並且輸入帳號密碼,執行後會回傳以下內容
Response body
{
"succeeded": true,
"isLockedOut": false,
"isNotAllowed": false,
"requiresTwoFactor": false
}
看到 "succeeded": true 就代表登入成功了,此時可以檢查瀏覽器的 Cookie
域名底下會發現多了一個 Cookie .AspNetCore.Identity.Application
我們在 WeatherForecastController
新增驗證,需要登入才可以使用此API
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
Summary
今天學習了 SignInManager
與使用 Cookie 來進行登入驗證,並且知道微軟已經內建提供了許多登入方式(Schema)
之後的文章會繼續試試看 JWT 或者第三方登入
今天的進度 Github