Skip to content

Commit

Permalink
Add CookieOrJwtBearerAuthenticationLab
Browse files Browse the repository at this point in the history
  • Loading branch information
Clark159 committed Jun 8, 2021
1 parent 6f4539d commit fd2b23b
Show file tree
Hide file tree
Showing 48 changed files with 921 additions and 947 deletions.
29 changes: 26 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
# CLK.AspNetCoreLab

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

本篇範例使用自定義的Middleware/Handler,展示如何在ASP.NET Core裡進行身分認證/身分授權
本篇範例展示如何在ASP.NET Core裡,同時使用Cookie及JwtBearer身分驗證機制

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

範例專案:AuthLab
範例專案:CookieOrJwtBearerAuthenticationLab

測試步驟:

- Account.Login、狀態:未登入
1. 點擊GetTokenByPassword按鈕,將會使用Username、Password進行身分驗證,並發放Token回傳。
2. 點擊GetUserByToken按鈕,將會使用步驟1取得的Token進行身分驗證,並回傳目前登入的User資料。(authenticationType="JwtBearer")
3. 點擊Login按鈕,將會使用Username、Password進行身分驗證,並發放Cookie後轉頁至Home頁面。

- Home.Index、狀態:未登入
1. 進入頁面後,會先顯示目前登入的User資料。(authenticationType="Cookies")
2. 點擊GetTokenByCookie按鈕,將會使用Cookie進行身分驗證,並發放Token回傳。
3. 點擊GetUserByToken按鈕,將會使用步驟1取得的Token進行身分驗證,並回傳目前登入的User資料。(authenticationType="JwtBearer")
4. 點擊GetUserByToken按鈕,將會使用Cookie進行身分驗證,並回傳目前登入的User資料。(authenticationType="Cookies")
5. 點擊Logout按鈕,將會刪除Cookie,並轉頁至Login頁面。


## [ASP.NET Core] Authenticate/Authorization 步驟流程範例

本篇範例使用自定義的Middleware/Handler,展示在ASP.NET Core裡進行身分認證/身分授權的步驟流程。

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

範例專案:KernelAuthenticationLab

執行結果:
- ![AuthLab執行結果](https://raw.githubusercontent.com/Clark159/CLK.AspNetCoreLab/master/doc/AuthLab/%E5%9F%B7%E8%A1%8C%E7%B5%90%E6%9E%9C.png)
Expand Down
File renamed without changes.
File renamed without changes.
33 changes: 8 additions & 25 deletions src/CLK.AspNetCoreLab.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ VisualStudioVersion = 16.0.30804.86
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AreaLab", "AreaLab\AreaLab.csproj", "{3312D580-D3DD-4F94-8607-8D7D298F272F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtAuthLab", "JwtAuthLab\JwtAuthLab.csproj", "{6FAE42CB-B825-4612-ABFF-452465CC2907}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PermissionLab", "PermissionLab\PermissionLab.csproj", "{0172F3CF-2704-4621-821F-16EDC38CE995}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WildcardMatchLab", "WildcardMatchLab\WildcardMatchLab.csproj", "{BAB117E8-9CA4-4242-B2F5-9225EF7A5758}"
Expand Down Expand Up @@ -45,14 +43,8 @@ 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}") = "JwtBearerAuthenticationLab", "JwtBearerAuthenticationLab\JwtBearerAuthenticationLab.csproj", "{A1631F3F-0D4E-4BEE-A36F-569919474121}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FacebookAuthenticationLab", "FacebookAuthenticationLab\FacebookAuthenticationLab.csproj", "{45D0015A-4AA1-42AC-A7DC-5BB7875539F0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Facebook2RegisterAuthenticationLab", "Facebook2RegisterAuthenticationLab\Facebook2RegisterAuthenticationLab.csproj", "{7F617D94-7575-4682-8AED-896A59EFA24B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Old", "Old", "{F2740F15-B2C6-42A9-9594-7D514613B6E8}"
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 @@ -63,7 +55,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "05.Authorization", "05.Auth
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "99.Other", "99.Other", "{2EF4759E-2FE8-4521-B4AC-ED3730283B37}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KernelAuthenticationLab", "KernelAuthenticationLab\KernelAuthenticationLab.csproj", "{D7579E02-831D-42A6-BA4F-C4D65BEA90AD}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KernelAuthenticationLab", "KernelAuthenticationLab\KernelAuthenticationLab.csproj", "{D7579E02-831D-42A6-BA4F-C4D65BEA90AD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CookieOrJwtBearerAuthenticationLab", "CookieOrJwtBearerAuthenticationLab\CookieOrJwtBearerAuthenticationLab.csproj", "{B928E9BA-B63F-4726-84C0-6E87BC18A828}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -75,10 +69,6 @@ Global
{3312D580-D3DD-4F94-8607-8D7D298F272F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3312D580-D3DD-4F94-8607-8D7D298F272F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3312D580-D3DD-4F94-8607-8D7D298F272F}.Release|Any CPU.Build.0 = Release|Any CPU
{6FAE42CB-B825-4612-ABFF-452465CC2907}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FAE42CB-B825-4612-ABFF-452465CC2907}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FAE42CB-B825-4612-ABFF-452465CC2907}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FAE42CB-B825-4612-ABFF-452465CC2907}.Release|Any CPU.Build.0 = Release|Any CPU
{0172F3CF-2704-4621-821F-16EDC38CE995}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0172F3CF-2704-4621-821F-16EDC38CE995}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0172F3CF-2704-4621-821F-16EDC38CE995}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -139,14 +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
{A1631F3F-0D4E-4BEE-A36F-569919474121}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1631F3F-0D4E-4BEE-A36F-569919474121}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1631F3F-0D4E-4BEE-A36F-569919474121}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1631F3F-0D4E-4BEE-A36F-569919474121}.Release|Any CPU.Build.0 = Release|Any CPU
{45D0015A-4AA1-42AC-A7DC-5BB7875539F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45D0015A-4AA1-42AC-A7DC-5BB7875539F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45D0015A-4AA1-42AC-A7DC-5BB7875539F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45D0015A-4AA1-42AC-A7DC-5BB7875539F0}.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
Expand All @@ -155,13 +137,16 @@ Global
{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
{D7579E02-831D-42A6-BA4F-C4D65BEA90AD}.Release|Any CPU.Build.0 = Release|Any CPU
{B928E9BA-B63F-4726-84C0-6E87BC18A828}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{3312D580-D3DD-4F94-8607-8D7D298F272F} = {89E18C8E-CF82-43F1-AC8A-DD0F89409EA2}
{6FAE42CB-B825-4612-ABFF-452465CC2907} = {F2740F15-B2C6-42A9-9594-7D514613B6E8}
{0172F3CF-2704-4621-821F-16EDC38CE995} = {82CBD2E0-D94E-4985-95EE-2807FF8F2423}
{BAB117E8-9CA4-4242-B2F5-9225EF7A5758} = {2EF4759E-2FE8-4521-B4AC-ED3730283B37}
{D48B0AA3-DD0B-45FE-B4F9-9A8C46302561} = {0E686910-AD0B-4AF4-B344-CFF4AF819DA3}
Expand All @@ -178,15 +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}
{A1631F3F-0D4E-4BEE-A36F-569919474121} = {4619D157-98EB-4180-A492-2EE070EDE1DA}
{45D0015A-4AA1-42AC-A7DC-5BB7875539F0} = {4619D157-98EB-4180-A492-2EE070EDE1DA}
{7F617D94-7575-4682-8AED-896A59EFA24B} = {4619D157-98EB-4180-A492-2EE070EDE1DA}
{F2740F15-B2C6-42A9-9594-7D514613B6E8} = {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}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CBB7D75C-988E-4A62-8EB5-C26F026248F5}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public async Task<ActionResult> Login(string username = null, string returnUrl =
if (string.IsNullOrEmpty(returnUrl) == true) returnUrl = @"/";
if (this.User.Identity.IsAuthenticated == true) return this.Redirect(returnUrl);

// Check
// Validate
// ...

// ClaimsPrincipal
Expand Down
3 changes: 2 additions & 1 deletion src/CookieAuthenticationLab/Views/Home/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
<hr />

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

<!--Logout-->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace CookieOrJwtBearerAuthenticationLab
{
[AllowAnonymous]
public partial class AccountController : Controller
{
// Fields
private readonly SecurityTokenFactory _tokenFactory;


// Constructors
public AccountController(SecurityTokenFactory tokenFactory)
{
#region Contracts

if (tokenFactory == null) throw new ArgumentException(nameof(tokenFactory));

#endregion

// Default
_tokenFactory = tokenFactory;
}


// Methods
public async Task<ActionResult> Login(string username = null, string password = null, 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
// ...

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

// SignIn
await this.HttpContext.SignInAsync(claimsPrincipal);

// Redirect
return this.Redirect(returnUrl);
}

public async Task<ActionResult> Logout()
{
// Require
if (this.User.Identity.IsAuthenticated == false) return this.Redirect(@"/");

// SignIn
await this.HttpContext.SignOutAsync();

// Redirect
return this.Redirect(@"/");
}
}

// GetUser
public partial class AccountController : Controller
{
// Methods
[Authorize]
public ActionResult<GetUserResultModel> GetUser([FromBody] GetUserActionModel actionModel)
{
#region Contracts

if (actionModel == null) throw new ArgumentException(nameof(actionModel));

#endregion

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

// Return
return (new GetUserResultModel()
{
User = user
});
}


// Class
public class GetUserActionModel
{
// Properties

}

public class GetUserResultModel
{
// Properties
public UserModel User { get; set; }
}

public class UserModel
{
// Properties
public string Username { get; set; }

public string AuthenticationType { get; set; }
}
}

// GetToken
public partial class AccountController : Controller
{
// Methods
[Authorize]
public ActionResult<GetTokenResultModel> GetToken([FromBody] GetTokenActionModel actionModel)
{
#region Contracts

if (actionModel == null) throw new ArgumentException(nameof(actionModel));

#endregion

// ClaimIdentity
var claimIdentity = this.User.Identity as ClaimsIdentity;
if (claimIdentity == null) throw new InvalidOperationException($"{nameof(claimIdentity)}=null");

// TokenString
var tokenString = _tokenFactory.CreateEncodedJwt(claimIdentity);
if (string.IsNullOrEmpty(tokenString) == true) throw new InvalidOperationException($"{nameof(tokenString)}=null");

// Return
return (new GetTokenResultModel()
{
Token = tokenString
});
}


// Class
public class GetTokenActionModel
{
// Properties

}

public class GetTokenResultModel
{
// Properties
public string Token { get; set; }
}
}

// GetTokenByPassword
public partial class AccountController : Controller
{
// Methods
[AllowAnonymous]
public ActionResult<GetTokenByPasswordResultModel> GetTokenByPassword([FromBody] GetTokenByPasswordActionModel actionModel)
{
#region Contracts

if (actionModel == null) throw new ArgumentException(nameof(actionModel));

#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
// ...

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

// TokenString
var tokenString = _tokenFactory.CreateEncodedJwt(claimIdentity.Claims);
if (string.IsNullOrEmpty(tokenString) == true) throw new InvalidOperationException($"{nameof(tokenString)}=null");

// Return
return (new GetTokenByPasswordResultModel()
{
Token = tokenString
});
}


// Class
public class GetTokenByPasswordActionModel
{
// Properties
public string Username { get; set; }

public string Password { get; set; }
}

public class GetTokenByPasswordResultModel
{
// Properties
public string Token { get; set; }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace CookieOrJwtBearerAuthenticationLab
{
public class HomeController : Controller
{
// Methods
[Authorize]
public ActionResult Index()
{
// Return
return View();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.2" />
</ItemGroup>

</Project>
Loading

0 comments on commit fd2b23b

Please sign in to comment.