ASP.NET Core 有提供身分認證 管理的功能,叫做 Identity,此外也有提供多種的驗證方式,但許多時候因為建立專案時就已經有包含進去了,通常很容易忽略如何從無到有的新增步驟,此篇文章特意整理相關的資訊
這篇會分兩部分,一是建立 Identity 的環境,二是如何使用 Google OAuth 的方式登入
前置環境設定
要新增 Identity 的功能到 asp.net core 的程式裡,需要在 Startup.cs 先做以下的設定
- 
預設前置條件,設定 Entity Framework,因為 Identity 預設需要 EF 的支援 a. EF Core 預設已經包含在 Microsoft.AspNetCore.All的套件包內,所以不需要另外安裝b. 設定連線字串,儲存參數的方式有很多種,這裡先用最簡單(但不推薦)的方式處理,細節請參閱。建立一個 appsettings.json檔案,並將資料庫連線字串存放在此1 
 2
 3
 4
 5
 6{ 
 "ConnectionStrings": {
 "DefaultConnection": "Data Source=<DB_IPAddress>;DataBase=<DBName>;Persist Security Info=True;User ID=<UserName>;Password=<UserPassword>"
 },
 }c. service 加入 EF 服務 1 
 2
 3
 4
 5
 6
 7public void ConfigureServices(IServiceCollection services) 
 {
 // Add framework services.
 services.AddDbContext<StreamDbContext>(options =>
 options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
 ...
 }d. 建立 StreamDbContext,並繼承IdentityDbContext<TUser>1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 
 using Microsoft.EntityFrameworkCore;
 using stream_tools.Models;
 namespace stream_tools
 {
 public class StreamDbContext : IdentityDbContext<ApplicationUser>
 {
 public StreamDbContext(DbContextOptions<StreamDbContext> options) : base(options) { }
 }
 }e. 使用 EF migration 更新資料表結構 1 
 2
 3
 4// 建立 Identity Store 所需要的資料表 
 dotnet ef migrations add <migration-name>
 // 更新至資料庫
 dotnet ef database updatef. 更新完成後,會多出以下的資料表  
- 
在 ConfigureServices的地方加入Identity的服務1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18using Microsoft.AspNetCore.Identity; 
 ...
 public class Startup
 {
 // 可取得設定檔內容
 public IConfiguration Configuration { get; set; }
 public Startup(IConfiguration configuration)
 {
 Configuration = configuration;
 }
 public void ConfigureServices(IServiceCollection services)
 {
 ...
 services.AddIdentity<ApplicationUser, IdentityRole>()
 .AddEntityFrameworkStores<StreamDbContext>()
 .AddDefaultTokenProviders();
 }
 }
- 
建立 ApplicationUserClass1 
 2
 3
 4
 5
 6
 7
 8
 9
 10using Microsoft.AspNetCore.Identity; 
 namespace stream_tools.Models
 {
 public class ApplicationUser : IdentityUser
 {
 // 資訊擴充使用
 }
 }
- 
在 Configure 的地方啟動服務 1 
 2
 3
 4
 5
 6public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
 {
 ...
 app.UseAuthentication();
 ...
 }
- 
因為需要 MVC 來提供頁面,所以也順便加入 MVC 的功能 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11public void ConfigureServices(IServiceCollection services) 
 {
 ...
 services.AddMvc();
 }
 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
 {
 ...
 app.UseMvc();
 ...
 }
設定 Google API
- 
首先前往 https://console.developers.google.com/projectselector/apis/library ,開立新專案或選取舊專案  
- 
開啟 Google+ API供登入使用 
- 
點選憑證,並新增 OAuth  
- 
選擇 網路應用程式,並填入以下資訊  
- 
這裡須留意的是 已授權的重新導向 URI,Identity 預設的路由是 signin-google,所以只需要替換前面的 port 號碼即可
- 
確定後會取得一份 client_id 和 secret 的資訊,我們需要將這資訊儲存到上面所建立的 appsetting.json檔案內 
設定 Google 登入
- 
在官網的文件中,文件將 用戶端 ID 與 用戶端密碼,分別使用 Authentication:Google:ClientId與Authentication:Google:ClientSecret1 
 2
 3
 4
 5
 6{ 
 ...
 "Authentication:Google:ClientId": "用戶端 ID",
 "Authentication:Google:ClientSecret": "用戶端密碼"
 }
- 
加入新的 Authentication 方式 1 
 2
 3
 4
 5
 6
 7
 8public void ConfigureServices(IServiceCollection services) 
 {
 services.AddAuthentication().AddGoogle(googleOptions =>
 {
 googleOptions.ClientId = Configuration["Authentication:Google:ClientId"];
 googleOptions.ClientSecret = Configuration["Authentication:Google:ClientSecret"];
 });
 }當然除了 google 之外,還有其他的服務可以使用,其他資訊補充在下面的參考資料內 
到這邊為止,基礎設定已經完成了。現在是在頁面上要怎麼使用,Controller 的動作又是如何呢?
Controller - View
View
如果是使用 Razor 的方式要產生第三方登入選項的方式,其實很簡單,只要透過 SignInManager.GetExternalAuthenticationSchemesAsync() 的方式就可以取得有開啟的選項
| 1 | @using stream_tools.Models | 
- 
loginProviders清單內的 provider ,內容如下 
- 
所以當按下按鈕時,就會做 Form Post 的動作到 Account/ExternalLogin的 Action
Controller (重點)
| 1 | [] | 
- 當此 Action 接受到前面頁面 Post 動作時,就會先將登入成功後要轉址的位址轉成 Url 的方式,這裡就會回到 Account/ExternalLoginCallback的地方
- signInManager.ConfigureExternalAuthenticationProperties再將額外的資訊包成一個 property 後再送給- Challenge method最後續的行為
- signInManager是一個用來控制使用者登入的 API,文件連結已列在下面的參考文件中
- Challenge是 ControllerBase 裡的方法之一,會建立出一個- ChallengeResult,ChellengerResult is an ActionResult that on execution invokes AuthenticationManager.ChallengeAsync.
- provider的值,就如上圖所顯示的,只是將 name 的值傳進來,而這裡是帶入- Google
- 當執行後就會跑到Google 登入帳號的畫面,當完成 Google 帳號登入後,就會回到 Account/ExternalLoginCallback的地方
| 1 | public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null) | 
- 當登入動作完成後回到 ExternalLoginCallbackAction 時會收到兩個資訊,一個是遠端授權的錯誤訊息,一個是登入成功後要轉址的位置
- 取得第三方授權請求的附加資訊,可透過 var info = await _signInManager.GetExternalLoginInfoAsync();的方式取得更多的資訊- 舉例,如果要取得 email,取得方法是 info.Principal.FindFirstValue(ClaimTypes.Email);
- ClaimTypes的 Enum 還有更多其他的項目可以使用
 
- 舉例,如果要取得 email,取得方法是 
- var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);- ExternalLoginSignInAsync的方法是當透過外部驗證方式成功後,回到系統內時,執行內部的登入動作,而回傳的結果,可用來判斷該使用者的狀況是否能繼續往下走
 
參數設定
- 
CallbackPath: 這個參數的值是設定 Google API 在 重新導向 URI 的內容,預設是 /signin-google,如果想要改變時,可以修改這個設定1 
 2
 3
 4
 5services.AddAuthentication().AddGoogle(googleOptions => 
 {
 googleOptions.CallbackPath = new PathString("/someurl-you-want");
 ...
 });
- 
Scope: 在登入 Google 帳號時,我們可以透過 Scope 設定要向登入者取得額外的資訊,設定方式是 1 
 2
 3
 4
 5services.AddAuthentication().AddGoogle(googleOptions => 
 {
 googleOptions.Scope.Add('..');
 ...
 });
結論
到這邊可以算是一個完整的第三方驗證的流程,我認為這裡的流程即使改成使用 web api 的方式,應該也是可以做到一樣的效果,這部分等我實作出來後,在分享出來