ASP.NET Core 3.0輕量級(jí)角色API控制授權(quán)庫
說明
ASP.NET Core 3.0 一個(gè) jwt 的輕量角色/用戶、單個(gè)API控制的授權(quán)認(rèn)證庫
最近得空,重新做一個(gè)角色授權(quán)庫,而之前做了一個(gè)角色授權(quán)庫,是利用微軟的默認(rèn)接口做的,查閱了很多文檔,因?yàn)槔斫獠粔?,所以最終做出了有問題。
之前的舊版本 https://github.com/whuanle/CZGL.Auth/tree/1.0.0
如果要使用微軟的默認(rèn)接口,我個(gè)人認(rèn)為過于繁雜,而且對(duì)于這部分的資料較少。。。
使用默認(rèn)接口實(shí)現(xiàn)授權(quán)認(rèn)證,可以參考我另一篇文章
ASP.NET Core 使用 JWT 自定義角色/策略授權(quán)需要實(shí)現(xiàn)的接口
得益于大笨熊哥的引導(dǎo),利用放假時(shí)間重新做了一個(gè),利用微軟本身的授權(quán)認(rèn)證,在此基礎(chǔ)上做拓展。特點(diǎn)是使用十分簡便,無需過多配置;因?yàn)楸旧頉]有“造輪子”,所以如果需要改造,也十分簡單。
此庫更新到 .Net Core 3.0 了,如果需要在 2.2X 上使用,可以到倉庫下載項(xiàng)目,然后把 Nuget 包換成 2.2 的。
感謝大笨熊哥的指導(dǎo)。
項(xiàng)目倉庫地址 https://github.com/whuanle/CZGL.Auth
一、定義角色、API、用戶
隨便新建一個(gè)網(wǎng)站或API項(xiàng)目,例如 MyAuth。
Nuget 里搜索 CZGL.Auth,按照 2.0.1 版本,或者使用 Package Manager 命令
Install-Package CZGL.Auth -Version 2.0.1
CZGL.Auth 設(shè)計(jì)思路是,網(wǎng)站可以存在多個(gè)角色、多個(gè)用戶、多個(gè)API,
一個(gè)角色擁有一些 API,可以添加或刪除角色或修改角色所有權(quán)訪問的 API;
一個(gè)用戶可以同時(shí)屬于幾個(gè)角色。
第一步要考慮網(wǎng)站的角色、用戶、API設(shè)計(jì),
CZGL.Auth 把這些信息存儲(chǔ)到內(nèi)存中,一個(gè)用戶擁有那幾個(gè)角色、一個(gè)角色具有哪些API的訪問權(quán)限。
角色跟 API 是對(duì)應(yīng)關(guān)系,用戶跟角色是多對(duì)多關(guān)系。
新建一個(gè)類 RoleService.cs ,引入 using CZGL.Auth.Services;,RoleService 繼承 ManaRole。
通過以下接口操作角色權(quán)限信息
protected bool AddRole(RoleModel role);
protected bool AddUser(UserModel user);
protected bool RemoveRole(string roleName);
protected bool RemoveUser(string userName);很明顯,添加/移除一個(gè)角色,添加/移除一個(gè)用戶
假如有 A、B、C 三個(gè)角色,
有 /A、/B、/C、/AB、/AC、/BC、/ABC 共7個(gè)API,設(shè)定權(quán)限
A 可以訪問 A、AB、AC、ABC
B 可以訪問 B、AB、BC、ABC
C 可以訪問 C、AC、BC、ABC
這里采用模擬數(shù)據(jù)的方法,不從數(shù)據(jù)庫里面加載實(shí)際數(shù)據(jù)。
在 RoleService 里面增加一個(gè)方法
/// <summary>
/// 用于加載角色和API
/// </summary>
public void UpdateRole()
{
List<RoleModel> roles = new List<RoleModel>
{
new RoleModel
{
RoleName="A",
Apis=new List<OneApiModel>
{
new OneApiModel
{
ApiName="A",
ApiUrl="/A"
},
new OneApiModel
{
ApiName="AB",
ApiUrl="/AB"
},
new OneApiModel
{
ApiName="AC",
ApiUrl="/AC"
},
new OneApiModel
{
ApiName="ABC",
ApiUrl="/ABC"
}
}
},
new RoleModel
{
RoleName="B",
Apis=new List<OneApiModel>
{
new OneApiModel
{
ApiName="B",
ApiUrl="/B"
},
new OneApiModel
{
ApiName="AB",
ApiUrl="/AB"
},
new OneApiModel
{
ApiName="BC",
ApiUrl="/BC"
},
new OneApiModel
{
ApiName="ABC",
ApiUrl="/ABC"
}
}
},
new RoleModel
{
RoleName="A",
Apis=new List<OneApiModel>
{
new OneApiModel
{
ApiName="A",
ApiUrl="/A"
},
new OneApiModel
{
ApiName="AB",
ApiUrl="/AB"
},
new OneApiModel
{
ApiName="AC",
ApiUrl="/AC"
},
new OneApiModel
{
ApiName="ABC",
ApiUrl="/ABC"
}
}
}
};
foreach (var item in roles)
{
AddRole(item);
}
}
有了角色和對(duì)應(yīng)的API信息,就要添加用戶了,
假設(shè)有 aa、bb、cc 三個(gè)用戶,密碼都是 123456,aa 屬于 A 角色, bb 屬于 B角色...
public void UpdateUser()
{
AddUser(new UserModel { UserName = "aa", BeRoles = new List<string> { "A" } });
AddUser(new UserModel { UserName = "bb", BeRoles = new List<string> { "B" } });
AddUser(new UserModel { UserName = "cc", BeRoles = new List<string> { "C" } });
}為了能夠把角色和用戶加載進(jìn) CZGL.Auth ,你需要在程序啟動(dòng)時(shí),例如在 Program 里,使用
RoleService roleService = new RoleService();
roleService.UpdateRole();
roleService.UpdateUser();二、添加自定義事件
授權(quán)是,可能會(huì)有各種情況,你可以添加自定義事件記錄下用戶訪問的授權(quán)信息、影響授權(quán)結(jié)果。
引用 using CZGL.Auth.Interface;,
添加一個(gè)類 RoleEvents 繼承 IRoleEventsHadner
public class RoleEvents : IRoleEventsHadner
{
public async Task Start(HttpContext httpContext)
{
await Task.CompletedTask;
}
public void TokenEbnormal(object eventsInfo)
{
}
public void TokenIssued(object eventsInfo)
{
}
public void NoPermissions(object eventsInfo)
{
}
public void Success(object eventsInfo)
{
}
public async Task End(HttpContext httpContext)
{
await Task.CompletedTask;
}
}在 CZGL.Auth 開始驗(yàn)證授權(quán)前調(diào)用 Start,結(jié)束時(shí)調(diào)用 End,傳入傳參數(shù)是 HttpContext 類型,你可以在里面添加自定義授權(quán)的信息,在里面可以影響請(qǐng)求管道。
其他幾個(gè)方法含義如下:
- TokenEbnormal 客戶端攜帶的 Token 不是有效的 Jwt 令牌,將不能被解析
- TokenIssued 令牌解碼后,issuer 或 audience不正確
- NoPermissions 無權(quán)訪問此 API
在授權(quán)認(rèn)證的各個(gè)階段將會(huì)調(diào)用上面的方法。
三、注入授權(quán)服務(wù)和中間件
使用 CZGL.Auth ,你需要注入以下兩個(gè)服務(wù)
services.AddRoleService(authOptions);
services.AddSingleton<IRoleEventsHadner, RoleEvents>();AddRoleService 是注入授權(quán)服務(wù),AddSingleton 注入你的事件。
AddRoleService 需要一個(gè) AuthConfigModel 類型作參數(shù)。
你可以這樣配置
var authOptions = new AuthBuilder()
.Security("aaaafsfsfdrhdhrejtrjrt", "ASPNETCORE", "ASPNETCORE")
.Jump("accoun/login", "account/error", false, false)
.Time(TimeSpan.FromMinutes(20))
.InfoScheme(new CZGL.Auth.Models.AuthenticateScheme
{
TokenEbnormal = "Login authentication failed!",
TokenIssued = "Login authentication failed!",
NoPermissions = "Login authentication failed!"
}).Build();
services.AddRoleService(authOptions);
services.AddSingleton<IRoleEventsHadner, RoleEvents>();Security 配置密鑰相關(guān),參數(shù)分別是密鑰字符串、頒發(fā)者、訂閱者。
Jump 配置授權(quán)失敗時(shí),跳轉(zhuǎn)地址。參數(shù)分別是未授權(quán)時(shí)跳轉(zhuǎn)、授權(quán)無效跳轉(zhuǎn),后面兩個(gè) bool 可以設(shè)置跳轉(zhuǎn)或跳轉(zhuǎn)。
Time 配置 Token 有效期。
InfoScheme 授權(quán)失敗提示信息,例如

上圖的是時(shí)間過期的提示消息,用戶請(qǐng)求API失敗時(shí)返回 401 狀態(tài)碼,Header 會(huì)攜帶提示消息,CZGL.Auth 里面設(shè)置了三種情況下,自定義頭部:
TokenEbnormal 客戶端攜帶的 Token 不是有效的 Jwt 令牌,將不能被解析
TokenIssued 令牌解碼后,issuer 或 audience不正確
NoPermissions 無權(quán)訪問此 API
添加三個(gè)中間件
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<RoleMiddleware>();app.UseAuthorization();是微軟授權(quán)認(rèn)證的中間件,CZGL.Auth 會(huì)先讓,默認(rèn)的驗(yàn)證管道過濾一些無效請(qǐng)求和認(rèn)證信息,再由 CZGL.Auth 來校驗(yàn)授權(quán)。
四、如何設(shè)置API的授權(quán)
很簡單,CZGL.Auth 的認(rèn)證授權(quán),你只需在 Controller 或 Action上 添加 [Authorize]。
CZGL.Auth 只會(huì)對(duì)使用了 [Authorize] 特性的 Controller 或 Action 生效。
如果一個(gè) Controller 已經(jīng)設(shè)置了 [Authorize] ,但是你想里面的 Action 跳過授權(quán)認(rèn)證,則使用 [AllowAnonymous] 修飾 Action。
使用方法跟微軟的默認(rèn)的完全一致。這樣無需過多配置。
如果你想另外定義一個(gè)特性用來另外設(shè)置 授權(quán)的話,可以到我的倉庫提 Issue 或者直接聯(lián)系我微信。
添加一個(gè) APIController ,
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
[HttpGet("/A")]
public JsonResult A()
{
return new JsonResult(new { Code = 200, Message = "Success!" });
}
[HttpGet("/B")]
public JsonResult B()
{
return new JsonResult(new { Code = 200, Message = "Success!" });
}
[HttpGet("/C")]
public JsonResult C()
{
return new JsonResult(new { Code = 200, Message = "Success!" });
}
[HttpGet("/AB")]
public JsonResult AB()
{
return new JsonResult(new { Code = 200, Message = "Success!" });
}
[HttpGet("/BC")]
public JsonResult BC()
{
return new JsonResult(new { Code = 200, Message = "Success!" });
}
[HttpGet("/AC")]
public JsonResult AC()
{
return new JsonResult(new { Code = 200, Message = "Success!" });
}
[HttpGet("/ABC")]
public JsonResult ABC()
{
return new JsonResult(new { claims = User.Claims });
}
/// <summary>
/// 任何人都不能訪問
/// </summary>
/// <returns></returns>
[HttpGet("D")]
public JsonResult D()
{
return new JsonResult(new { Code = 200, Message = "Success!" });
}
[HttpGet("error")]
public JsonResult Denied()
{
return new JsonResult(
new
{
Code = 0,
Message = "訪問失敗!",
Data = "此賬號(hào)無權(quán)訪問!"
});
}
}五、添加登錄頒發(fā) Token
添加一個(gè) AccountController.cs 用來頒發(fā)登錄、 Token。
[Route("api/[controller]")]
[ApiController]
public class AccountController : ControllerBase
{
[HttpPost("/Login")]
public async Task<JsonResult> Login([FromQuery]string username, string password, string rolename)
{
// 用戶名密碼是否正確
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password) || string.IsNullOrWhiteSpace(rolename))
{
return new JsonResult(new
{
Code = 0,
Message = "尼瑪,上傳什么垃圾信息",
});
}
if(!((username=="aa"||username=="bb"||username=="cc")&&password=="123456"))
{
return new JsonResult(new
{
Code = 0,
Message = "賬號(hào)或密碼錯(cuò)誤",
});
}
// 你自己定義的角色/用戶信息服務(wù)
RoleService roleService = new RoleService();
// 檢驗(yàn)用戶是否屬于此角色
var role = roleService.IsUserToRole(username,rolename);
// CZGL.Auth 中一個(gè)用于加密解密的類
EncryptionHash hash = new EncryptionHash();
// 設(shè)置用戶標(biāo)識(shí)
var userClaims = hash.BuildClaims(username, rolename);
//// 自定義構(gòu)建配置用戶標(biāo)識(shí)
/// 自定義的話,至少包含如下標(biāo)識(shí)
//var userClaims = new Claim[]
//{
//new Claim(ClaimTypes.Name, userName),
// new Claim(ClaimTypes.Role, roleName),
// new Claim(JwtRegisteredClaimNames.Aud, Audience),
// new Claim(ClaimTypes.Expiration, TimeSpan.TotalSeconds.ToString()),
// new Claim(JwtRegisteredClaimNames.Iat, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString())
//};
/*
iss (issuer):簽發(fā)人
exp (expiration time):過期時(shí)間
sub (subject):主題
aud (audience):受眾
nbf (Not Before):生效時(shí)間
iat (Issued At):簽發(fā)時(shí)間
jti (JWT ID):編號(hào)
*/
// 方法一,直接頒發(fā) Token
ResponseToken token = hash.BuildToken(userClaims);
//方法二,拆分多步,頒發(fā) token,方便調(diào)試
//var identity = hash.GetIdentity(userClaims);
//var jwt = hash.BuildJwtToken(userClaims);
//var token = hash.BuildJwtResponseToken(jwt);
return new JsonResult(token);
}
}六、部分說明
注入 Jwt 服務(wù)、頒發(fā) Token
CZGL.Auth 把使用 jwt 的服務(wù)和頒發(fā) Token 的代碼封裝好了,這個(gè)庫不是在“造輪子”,所以實(shí)際上你可以很輕松的把這部分的代碼抽出來,另外設(shè)計(jì)。
這部分的代碼所在位置 RoleServiceExtension.cs 、EncryptionHash.cs。
授權(quán)中間件
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<RoleMiddleware>();我的寫法是利用 ASP.NET Core 的 jwt 完成基礎(chǔ)的認(rèn)證授權(quán),然后在下一個(gè)管道中實(shí)現(xiàn)拓展的認(rèn)證。但是本身的認(rèn)證是在 app.UseAuthorization(); 做了拓展,所以使用 CZGL.Auth,只需要按照平常 jwt 的方式去使用,只是加了一個(gè) RoleMiddleware 中間件。
CZGL.Auth 只是我受到新思路啟發(fā)臨時(shí)寫出來的。。。最好不要直接用于生產(chǎn),去 github 庫把項(xiàng)目下載下來,按照自己應(yīng)用場(chǎng)景改一下~。
七、驗(yàn)證
先使用 aa 用戶登錄,登錄時(shí)選擇 A 角色。

因?yàn)?A 用戶只能訪問 “帶有 A ” 的API, "/A"、"/AB" 等,所以我們可以試試。

繼續(xù)用這個(gè) Token 訪問一下 "/B"

可以繼續(xù)嘗試添加 API 或者使用其他用戶登錄,訪問不同的 API。
由于別人對(duì)前端不熟,所以就不寫帶頁面的示例了~。
可以用 Postman 就行測(cè)試。
什么示例的 項(xiàng)目可以到倉庫里下載,名稱是 MyAuth。
一般上,用戶權(quán)限、角色權(quán)限信息是存儲(chǔ)在數(shù)據(jù)庫里面的,另一個(gè)示例是 CZGL.Auth.Sample2。
這個(gè)庫只是較為粗略的授權(quán)認(rèn)證,與更豐富的需求請(qǐng)自行下載源碼修改~
到此這篇關(guān)于ASP.NET Core 3.0輕量級(jí)角色API控制授權(quán)庫的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- asp.net core 認(rèn)證和授權(quán)實(shí)例詳解
- ASP.NET?Core?6.0?添加?JWT?認(rèn)證和授權(quán)功能
- ASP.NET?Core中的策略授權(quán)和ABP授權(quán)
- ASP.NET Core使用JWT自定義角色并實(shí)現(xiàn)策略授權(quán)需要的接口
- asp.net core3.1cookie和jwt混合認(rèn)證授權(quán)實(shí)現(xiàn)多種身份驗(yàn)證方案
- ASP.NET Core使用JWT認(rèn)證授權(quán)的方法
- ASP.NET Core學(xué)習(xí)之使用JWT認(rèn)證授權(quán)詳解
- 淺談ASP.NET Core 中jwt授權(quán)認(rèn)證的流程原理
- asp.net core 授權(quán)詳解
- asp.net core2.2多用戶驗(yàn)證與授權(quán)示例詳解
- asp.net core項(xiàng)目授權(quán)流程詳解
相關(guān)文章
ASP.NET Core+Docker+Jenkins實(shí)現(xiàn)持續(xù)集成的完整實(shí)例
這篇文章主要給大家介紹了關(guān)于ASP.NET Core+Docker+Jenkins實(shí)現(xiàn)持續(xù)集成的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05
如何利用FluentMigrator實(shí)現(xiàn)數(shù)據(jù)庫遷移
這篇文章主要給大家介紹了關(guān)于如何利用FluentMigrator實(shí)現(xiàn)數(shù)據(jù)庫遷移的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
asp.net動(dòng)態(tài)獲取Excel表名的函數(shù)代碼
asp.net動(dòng)態(tài)獲取Excel表名的函數(shù)代碼,需要的朋友可以參考下。2011-02-02
asp.net中Datalist使用數(shù)字分頁的實(shí)現(xiàn)方法
asp.net下Datalist使用數(shù)字分頁的實(shí)現(xiàn)代碼,需要的朋友可以參考下。2010-10-10
asp.net下生成英文字符數(shù)字驗(yàn)證碼的代碼
用了asp.net隨機(jī)數(shù),獲取指定位數(shù)的字母或數(shù)字以后,進(jìn)行圖片輸出的驗(yàn)證碼函數(shù)。2009-12-12
Entity Framework使用Code First模式管理事務(wù)
本文詳細(xì)講解了Entity Framework使用Code First模式管理事務(wù)的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03

