Skip to content

Commit

Permalink
Add OAuthToRegisterAuthenticationLab
Browse files Browse the repository at this point in the history
  • Loading branch information
Clark159 committed Jun 14, 2021
1 parent 061ceb9 commit 98225cf
Show file tree
Hide file tree
Showing 44 changed files with 1,179 additions and 146 deletions.
50 changes: 49 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,56 @@
# CLK.AspNetCoreLab

## [ASP.NET Core] OAuth驗證後註冊的身分驗證範例

本篇範例展示如何在ASP.NET Core裡,使用OAuth驗證後要求用戶註冊,註冊完成才允許登入的身分驗證機制。(已註冊過直接登入)

範例原碼:https://github.com/Clark159/CLK.AspNetCoreLab

範例專案:OAuthToRegisterAuthenticationLab

環境準備:

- Google OAuth
1. 至Google建立專案,並申請OAuth2.0用戶端。(https://console.cloud.google.com/home)
2. 於申請OAuth頁面的「已授權的重新導向URI」欄位,輸入https://localhost:44311/Account/Google-OAuth-SignIn
3. 於申請OAuth頁面取得ClientId、ClientSecret。
4. 將上一個步驟取得的ClientId、ClientSecret,填寫至Startup.cs的AddGoogle程式碼區塊內。

- Facebook OAuth
1. 至Facebook建立應用程式,並申請Facebook登入。(https://developers.facebook.com/apps/)
2. 於申請Facebook登入頁面的「有效的 OAuth 重新導向 URI」欄位,輸入https://localhost:44311/Account/Facebook-OAuth-SignIn
3. 於設定\基本資料頁面取得ClientId、ClientSecret。
4. 將上一個步驟取得的ClientId、ClientSecret,填寫至Startup.cs的AddFacebook程式碼區塊內。

測試步驟:

- OAuth登入後進行註冊,狀態:用戶資料未註冊
1. 於LocalHost網站的Account.Login頁面點擊LoginByGoogle按鈕,執行Account.ExternalLogin,並開啟Google網站進行OAuth的登入及授權。
2. (背景作業)Google完成OAuth的登入及授權後,重新導向至https://localhost:44311/Account/Google-OAuth-SignIn。
3. (背景作業)LocalHost網站將Google回傳的OAuth授權資料,儲存至ExternalCookie,並導頁至Account.ExternalSignIn。
4. (背景作業)LocalHost網站執行Account.ExternalSignIn,使用ExternalCookie的OAuth授權資料,確認用戶沒有註冊資訊後,導頁至Account.Register。
5. 於LocalHost網站的Account.Register頁面,填寫註冊資料後點擊Register按鈕完成用戶註冊後,將用戶資訊儲存至ApplicationCookie並轉頁至Home.Index頁面。(已登入)
6. 於LocalHost網站的Home.Index頁面,可以看到目前登入的用戶資訊。:已登入,使用Google-OAuth。
7. 於LocalHost網站的Home.Index頁面點擊Logout按鈕,進行登出後完成測試。

- OAuth登入後無須註冊,狀態:用戶資料已註冊
1. 於LocalHost網站的Account.Login頁面點擊LoginByGoogle按鈕,執行Account.ExternalLogin,並開啟Google網站進行OAuth的登入及授權。
2. (背景作業)Google完成OAuth的登入及授權後,重新導向至https://localhost:44311/Account/Google-OAuth-SignIn。
3. (背景作業)LocalHost網站將Google回傳的OAuth授權資料,儲存至ExternalCookie,並導頁至Account.ExternalSignIn。
4. (背景作業)LocalHost網站執行Account.ExternalSignIn,使用ExternalCookie的OAuth授權資料,確認用戶擁有註冊資訊後,將用戶資訊儲存至ApplicationCookie並轉頁至Home.Index頁面。(已登入)
5. 於LocalHost網站的Home.Index頁面,可以看到目前登入的用戶資訊:已登入,使用Google-OAuth。
6. 於LocalHost網站的Home.Index頁面點擊Logout按鈕,進行登出後完成測試。

- Password登入後無須註冊,狀態:用戶資料已註冊
1. 於LocalHost網站的Account.Login頁面點擊LoginByPassword按鈕,執行Account.PasswordSignIn。
2. (背景作業)LocalHost網站執行Account.PasswordSignIn,確認用戶密碼(Hash)後,將用戶資訊儲存至ApplicationCookie並轉頁至Home.Index頁面。(已登入)
3. 於LocalHost網站的Home.Index頁面,可以看到目前登入的用戶資訊:已登入,使用Password。
4. 於LocalHost網站的Home.Index頁面點擊Logout按鈕,進行登出後完成測試。


## [ASP.NET Core] Cookie/JwtBearer並存的身分驗證範例

本篇範例展示如何在ASP.NET Core裡,同時使用Cookie及JwtBearer身分驗證機制
本篇範例展示如何在ASP.NET Core裡,同時使用Cookie及JwtBearer的身分驗證機制

範例原碼:https://github.com/Clark159/CLK.AspNetCoreLab

Expand Down
14 changes: 7 additions & 7 deletions src/CLK.AspNetCoreLab.sln
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "04.Authentication", "04.Aut
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CookieAuthenticationLab", "CookieAuthenticationLab\CookieAuthenticationLab.csproj", "{F473924C-4A62-497E-BF11-EBC229A9944F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Facebook2RegisterAuthenticationLab", "Facebook2RegisterAuthenticationLab\Facebook2RegisterAuthenticationLab.csproj", "{7F617D94-7575-4682-8AED-896A59EFA24B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "03.Module", "03.Module", "{0E686910-AD0B-4AF4-B344-CFF4AF819DA3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "01.Setting", "01.Setting", "{E09476D2-16DD-4898-829B-0917EFCF4B0C}"
Expand All @@ -59,6 +57,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KernelAuthenticationLab", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CookieOrJwtBearerAuthenticationLab", "CookieOrJwtBearerAuthenticationLab\CookieOrJwtBearerAuthenticationLab.csproj", "{B928E9BA-B63F-4726-84C0-6E87BC18A828}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OAuthToRegisterAuthenticationLab", "OAuthToRegisterAuthenticationLab\OAuthToRegisterAuthenticationLab.csproj", "{4BB42B13-31E2-485B-9CF4-8907A97D13CA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -129,10 +129,6 @@ Global
{F473924C-4A62-497E-BF11-EBC229A9944F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F473924C-4A62-497E-BF11-EBC229A9944F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F473924C-4A62-497E-BF11-EBC229A9944F}.Release|Any CPU.Build.0 = Release|Any CPU
{7F617D94-7575-4682-8AED-896A59EFA24B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F617D94-7575-4682-8AED-896A59EFA24B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F617D94-7575-4682-8AED-896A59EFA24B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F617D94-7575-4682-8AED-896A59EFA24B}.Release|Any CPU.Build.0 = Release|Any CPU
{D7579E02-831D-42A6-BA4F-C4D65BEA90AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7579E02-831D-42A6-BA4F-C4D65BEA90AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7579E02-831D-42A6-BA4F-C4D65BEA90AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -141,6 +137,10 @@ Global
{B928E9BA-B63F-4726-84C0-6E87BC18A828}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B928E9BA-B63F-4726-84C0-6E87BC18A828}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B928E9BA-B63F-4726-84C0-6E87BC18A828}.Release|Any CPU.Build.0 = Release|Any CPU
{4BB42B13-31E2-485B-9CF4-8907A97D13CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4BB42B13-31E2-485B-9CF4-8907A97D13CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4BB42B13-31E2-485B-9CF4-8907A97D13CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4BB42B13-31E2-485B-9CF4-8907A97D13CA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -163,13 +163,13 @@ Global
{79FD7C8F-73E0-4A58-B62B-81B8393B7700} = {0E686910-AD0B-4AF4-B344-CFF4AF819DA3}
{4619D157-98EB-4180-A492-2EE070EDE1DA} = {89E18C8E-CF82-43F1-AC8A-DD0F89409EA2}
{F473924C-4A62-497E-BF11-EBC229A9944F} = {4619D157-98EB-4180-A492-2EE070EDE1DA}
{7F617D94-7575-4682-8AED-896A59EFA24B} = {4619D157-98EB-4180-A492-2EE070EDE1DA}
{0E686910-AD0B-4AF4-B344-CFF4AF819DA3} = {89E18C8E-CF82-43F1-AC8A-DD0F89409EA2}
{E09476D2-16DD-4898-829B-0917EFCF4B0C} = {89E18C8E-CF82-43F1-AC8A-DD0F89409EA2}
{19FFF031-5998-4B25-A4EB-A60F975920F2} = {89E18C8E-CF82-43F1-AC8A-DD0F89409EA2}
{39291E0E-6BAF-4A9E-9C37-552F31077C43} = {89E18C8E-CF82-43F1-AC8A-DD0F89409EA2}
{D7579E02-831D-42A6-BA4F-C4D65BEA90AD} = {4619D157-98EB-4180-A492-2EE070EDE1DA}
{B928E9BA-B63F-4726-84C0-6E87BC18A828} = {4619D157-98EB-4180-A492-2EE070EDE1DA}
{4BB42B13-31E2-485B-9CF4-8907A97D13CA} = {4619D157-98EB-4180-A492-2EE070EDE1DA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CBB7D75C-988E-4A62-8EB5-C26F026248F5}
Expand Down
30 changes: 23 additions & 7 deletions src/CookieAuthenticationLab/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,38 @@

namespace CookieAuthenticationLab
{
[AllowAnonymous]
public class AccountController : Controller
{
// Methods
public async Task<ActionResult> Login(string username = null, string returnUrl = @"/")
// Methods
[HttpGet]
[AllowAnonymous]
public ActionResult Login(string returnUrl = @"/")
{
// Require
if (string.IsNullOrEmpty(username) == true) return View();
if (string.IsNullOrEmpty(returnUrl) == true) returnUrl = @"/";
if (this.User.Identity.IsAuthenticated == true) return this.Redirect(returnUrl);

// Validate
// Return
return View();
}

[AllowAnonymous]
public async Task<ActionResult> Login(string userName, string password = null, string returnUrl = @"/")
{
#region Contracts

if (string.IsNullOrEmpty(userName) == true) throw new ArgumentException(nameof(userName));

#endregion

// Require
if (this.User.Identity.IsAuthenticated == true) return this.Redirect(returnUrl);

// Validate Password
// ...

// ClaimsPrincipal
var claimIdentity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
claimIdentity.AddClaim(new Claim(ClaimTypes.Name, username));
claimIdentity.AddClaim(new Claim(ClaimTypes.Name, userName));
var claimsPrincipal = new ClaimsPrincipal(claimIdentity);

// SignIn
Expand All @@ -36,6 +51,7 @@ public async Task<ActionResult> Login(string username = null, string returnUrl =
return this.Redirect(returnUrl);
}

[AllowAnonymous]
public async Task<ActionResult> Logout()
{
// Require
Expand Down
5 changes: 3 additions & 2 deletions src/CookieAuthenticationLab/Views/Account/Login.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
<!--Login-->
<form asp-controller="Account" asp-action="Login" asp-route-returnUrl="@Context.Request.Query["ReturnUrl"]" method="post">
<input type="submit" value="Login" /><br />
Username:<input type="text" name="username" value="Clark" /><br />
<hr />
UserName:<input type="text" name="userName" value="Clark" /><br />
<br />
</form>
<hr />

</body>
</html>
2 changes: 1 addition & 1 deletion src/CookieAuthenticationLab/Views/Home/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<hr />

<!--User-->
Username= @User.Identity.Name<br />
UserName= @User.Identity.Name<br />
AuthType= @User.Identity.AuthenticationType<br />
<hr />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,36 @@ public AccountController(SecurityTokenFactory tokenFactory)
}


// Methods
// Methods
[HttpGet]
[AllowAnonymous]
public ActionResult Login(string returnUrl = @"/")
{
// Require
if (this.User.Identity.IsAuthenticated == true) return this.Redirect(returnUrl);

// Return
return View();
}

[AllowAnonymous]
public async Task<ActionResult> Login(string username = null, string password = null, string returnUrl = @"/")
public async Task<ActionResult> Login(string userName, string password = null, string returnUrl = @"/")
{
#region Contracts

if (string.IsNullOrEmpty(userName) == true) throw new ArgumentException(nameof(userName));

#endregion

// Require
if (string.IsNullOrEmpty(username) == true) return View();
if (string.IsNullOrEmpty(returnUrl) == true) returnUrl = @"/";
if (this.User.Identity.IsAuthenticated == true) return this.Redirect(returnUrl);

// Validate
// Validate Password
// ...

// ClaimsPrincipal
var claimIdentity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
claimIdentity.AddClaim(new Claim(ClaimTypes.Name, username));
claimIdentity.AddClaim(new Claim(ClaimTypes.Name, userName));
var claimsPrincipal = new ClaimsPrincipal(claimIdentity);

// SignIn
Expand Down Expand Up @@ -83,7 +98,7 @@ public ActionResult<GetUserResultModel> GetUser([FromBody] GetUserActionModel ac

// UserModel
var user = new UserModel();
user.Username = this.User.Identity.Name;
user.UserName = this.User.Identity.Name;
user.AuthenticationType = this.User.Identity.AuthenticationType;

// Return
Expand All @@ -110,7 +125,7 @@ public class GetUserResultModel
public class UserModel
{
// Properties
public string Username { get; set; }
public string UserName { get; set; }

public string AuthenticationType { get; set; }
}
Expand Down Expand Up @@ -173,15 +188,14 @@ public ActionResult<GetTokenByPasswordResultModel> GetTokenByPassword([FromBody]
#endregion

// Require
if (string.IsNullOrEmpty(actionModel.Username) == true) throw new InvalidOperationException($"{nameof(actionModel.Username)}=null");
if (string.IsNullOrEmpty(actionModel.Password) == true) throw new InvalidOperationException($"{nameof(actionModel.Password)}=null");

// Validate
if (string.IsNullOrEmpty(actionModel.UserName) == true) throw new InvalidOperationException($"{nameof(actionModel.UserName)}=null");

// Validate Password
// ...

// ClaimIdentity
var claimIdentity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
claimIdentity.AddClaim(new Claim(ClaimTypes.Name, actionModel.Username));
claimIdentity.AddClaim(new Claim(ClaimTypes.Name, actionModel.UserName));

// TokenString
var tokenString = _tokenFactory.CreateEncodedJwt(claimIdentity.Claims);
Expand All @@ -199,7 +213,7 @@ public ActionResult<GetTokenByPasswordResultModel> GetTokenByPassword([FromBody]
public class GetTokenByPasswordActionModel
{
// Properties
public string Username { get; set; }
public string UserName { get; set; }

public string Password { get; set; }
}
Expand Down
1 change: 1 addition & 0 deletions src/CookieOrJwtBearerAuthenticationLab/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public void ConfigureServices(IServiceCollection services)
// Action
options.LoginPath = new PathString("/Account/Login");
options.LogoutPath = new PathString("/Account/Logout");
options.AccessDeniedPath = options.LoginPath;
})
.AddJwtBearer(options =>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#nullable enable

using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public string CreateEncodedJwt(ClaimsIdentity identity)

// ClaimList
var claimList = new List<Claim>(identity.Claims);
claimList.Add(new Claim(ClaimTypes.Name, identity.Name)); // Username
claimList.Add(new Claim(ClaimTypes.Name, identity.Name)); // UserName

// CreateEncodedJwt
return this.CreateEncodedJwt(claimList);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
document.getElementById("getTokenByPassword.button").addEventListener("click", event => {
// Variables
var username = document.getElementById("getTokenByPassword.username").value;
var userName = document.getElementById("getTokenByPassword.userName").value;
var password = document.getElementById("getTokenByPassword.password").value;
// ActionModel
var actionModel = {};
actionModel.username = username;
actionModel.password = "12345";
actionModel.userName = userName;
actionModel.password = password;
// Post
postRequst("/Account/GetTokenByPassword", actionModel)
Expand Down Expand Up @@ -79,14 +80,15 @@
<!--Login-->
<form asp-controller="Account" asp-action="Login" asp-route-returnUrl="@Context.Request.Query["ReturnUrl"]" method="post">
<input type="submit" value="Login" /><br />
Username:<input type="text" name="username" value="Clark" /><br />
UserName:<input type="text" name="userName" value="Clark" /><br />
<br />
</form>
<hr />

<!--GetTokenByPassword-->
<input id="getTokenByPassword.button" type="button" value="GetTokenByPassword" /><br />
Username:<input id="getTokenByPassword.username" type="text" value="Clark" /><br />
UserName:<input id="getTokenByPassword.userName" type="text" value="Clark" /><br />
Password:<input id="getTokenByPassword.password" type="password" value="" /><br />
<div id="getTokenByPassword.result"></div><br />
<hr />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
<hr />

<!--User-->
Username= @User.Identity.Name<br />
UserName= @User.Identity.Name<br />
AuthenticationType= @User.Identity.AuthenticationType<br />
<hr />

Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit 98225cf

Please sign in to comment.