ASP.NET Core 3.0 一个 jwt 的轻量角色/用户、单个API控制的授权认证库
说明
ASP.NET Core 3.0 一个 jwt 的轻量角色/用户、单个API控制的授权认证库
最近得空,重新做一个角色授权库,而之前做了一个角色授权库,是利用微软的默认接口做的,查阅了很多文档,因为理解不够,所以最终做出了有问题。
之前的旧版本 https://github.com/whuanle/CZGL.Auth/tree/1.0.0
如果要使用微软的默认接口,我个人认为过于繁杂,而且对于这部分的资料较少。。。
使用默认接口实现授权认证,可以参考我另一篇文章
ASP.NET Core 使用 JWT 自定义角色/策略授权需要实现的接口
得益于大笨熊哥的引导,利用放假时间重新做了一个,利用微软本身的授权认证,在此基础上做拓展。特点是使用十分简便,无需过多配置;因为本身没有“造轮子”,所以如果需要改造,也十分简单。
此库更新到 .Net Core 3.0 了,如果需要在 2.2X 上使用,可以到仓库下载项目,然后把 Nuget 包换成 2.2 的。
感谢大笨熊哥的指导。
项目仓库地址 https://github.com/whuanle/CZGL.Auth
一、定义角色、API、用户
随便新建一个网站或API项目,例如 MyAuth。
Nuget 里搜索 CZGL.Auth,按照 2.0.1 版本,或者使用 Package Manager 命令
Install-Package CZGL.Auth -Version 2.0.1
CZGL.Auth 设计思路是,网站可以存在多个角色、多个用户、多个API,
一个角色拥有一些 API,可以添加或删除角色或修改角色所有权访问的 API;
一个用户可以同时属于几个角色。
第一步要考虑网站的角色、用户、API设计,
CZGL.Auth 把这些信息存储到内存中,一个用户拥有那几个角色、一个角色具有哪些API的访问权限。
角色跟 API 是对应关系,用户跟角色是多对多关系。
新建一个类 RoleService.cs ,引入 using CZGL.Auth.Services;,RoleService 继承 ManaRole。
通过以下接口操作角色权限信息
protected bool AddRole(RoleModel role);
protected bool AddUser(UserModel user);
protected bool RemoveRole(string roleName);
protected bool RemoveUser(string userName);
很明显,添加/移除一个角色,添加/移除一个用户
假如有 A、B、C 三个角色,
有 /A、/B、/C、/AB、/AC、/BC、/ABC 共7个API,设定权限
A 可以访问 A、AB、AC、ABC
B 可以访问 B、AB、BC、ABC
C 可以访问 C、AC、BC、ABC
这里采用模拟数据的方法,不从数据库里面加载实际数据。
在 RoleService 里面增加一个方法
/// <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);
}
}
有了角色和对应的API信息,就要添加用户了,
假设有 aa、bb、cc 三个用户,密码都是 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" } });
}
为了能够把角色和用户加载进 CZGL.Auth ,你需要在程序启动时,例如在 Program 里,使用
RoleService roleService = new RoleService();
roleService.UpdateRole();
roleService.UpdateUser();
二、添加自定义事件
授权是,可能会有各种情况,你可以添加自定义事件记录下用户访问的授权信息、影响授权结果。
引用 using CZGL.Auth.Interface;,
添加一个类 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 开始验证授权前调用 Start,结束时调用 End,传入传参数是 HttpContext 类型,你可以在里面添加自定义授权的信息,在里面可以影响请求管道。
其他几个方法含义如下:
TokenEbnormal 客户端携带的 Token 不是有效的 Jwt 令牌,将不能被解析
TokenIssued 令牌解码后,issuer 或 audience不正确
NoPermissions 无权访问此 API
在授权认证的各个阶段将会调用上面的方法。
三、注入授权服务和中间件
使用 CZGL.Auth ,你需要注入以下两个服务
services.AddRoleService(authOptions);
services.AddSingleton<IRoleEventsHadner, RoleEvents>();
AddRoleService 是注入授权服务,AddSingleton 注入你的事件。
AddRoleService 需要一个 AuthConfigModel 类型作参数。
你可以这样配置
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 配置密钥相关,参数分别是密钥字符串、颁发者、订阅者。
Jump 配置授权失败时,跳转地址。参数分别是未授权时跳转、授权无效跳转,后面两个 bool 可以设置跳转或跳转。
Time 配置 Token 有效期。
InfoScheme 授权失败提示信息,例如

上图的是时间过期的提示消息,用户请求API失败时返回 401 状态码,Header 会携带提示消息,CZGL.Auth 里面设置了三种情况下,自定义头部:
TokenEbnormal 客户端携带的 Token 不是有效的 Jwt 令牌,将不能被解析
TokenIssued 令牌解码后,issuer 或 audience不正确
NoPermissions 无权访问此 API
添加三个中间件
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<RoleMiddleware>();
app.UseAuthorization();是微软授权认证的中间件,CZGL.Auth 会先让,默认的验证管道过滤一些无效请求和认证信息,再由 CZGL.Auth 来校验授权。
三、如何设置API的授权
很简单,CZGL.Auth 的认证授权,你只需在 Controller 或 Action上 添加 [Authorize]。
CZGL.Auth 只会对使用了 [Authorize] 特性的 Controller 或 Action 生效。
如果一个 Controller 已经设置了 [Authorize] ,但是你想里面的 Action 跳过授权认证,则使用 [AllowAnonymous] 修饰 Action。
使用方法跟微软的默认的完全一致。这样无需过多配置。
如果你想另外定义一个特性用来另外设置 授权的话,可以到我的仓库提 Issue 或者直接联系我微信。
添加一个 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 = "此账号无权访问!"
});
}
}
四、添加登录颁发 Token
添加一个 AccountController.cs 用来颁发登录、 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 = "账号或密码错误",
});
}
// 你自己定义的角色/用户信息服务
RoleService roleService = new RoleService();
// 检验用户是否属于此角色
var role = roleService.IsUserToRole(username,rolename);
// CZGL.Auth 中一个用于加密解密的类
EncryptionHash hash = new EncryptionHash();
// 设置用户标识
var userClaims = hash.BuildClaims(username, rolename);
//// 自定义构建配置用户标识
/// 自定义的话,至少包含如下标识
//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):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
*/
// 方法一,直接颁发 Token
ResponseToken token = hash.BuildToken(userClaims);
//方法二,拆分多步,颁发 token,方便调试
//var identity = hash.GetIdentity(userClaims);
//var jwt = hash.BuildJwtToken(userClaims);
//var token = hash.BuildJwtResponseToken(jwt);
return new JsonResult(token);
}
}
五、部分说明
注入 Jwt 服务、颁发 Token
CZGL.Auth 把使用 jwt 的服务和颁发 Token 的代码封装好了,这个库不是在“造轮子”,所以实际上你可以很轻松的把这部分的代码抽出来,另外设计。
这部分的代码所在位置 RoleServiceExtension.cs 、EncryptionHash.cs。
授权中间件
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<RoleMiddleware>();
我的写法是利用 ASP.NET Core 的 jwt 完成基础的认证授权,然后在下一个管道中实现拓展的认证。但是本身的认证是在 app.UseAuthorization(); 做了拓展,所以使用 CZGL.Auth,只需要按照平常 jwt 的方式去使用,只是加了一个 RoleMiddleware 中间件。
CZGL.Auth 只是我受到新思路启发临时写出来的。。。最好不要直接用于生产,去 github 库把项目下载下来,按照自己应用场景改一下~。
六、验证
先使用 aa 用户登录,登录时选择 A 角色。

因为 A 用户只能访问 “带有 A ” 的API, "/A"、"/AB" 等,所以我们可以试试。

继续用这个 Token 访问一下 "/B"

可以继续尝试添加 API 或者使用其他用户登录,访问不同的 API。
由于别人对前端不熟,所以就不写带页面的示例了~。
可以用 Postman 就行测试。
什么示例的 项目可以到仓库里下载,名称是 MyAuth。
一般上,用户权限、角色权限信息是存储在数据库里面的,另一个示例是 CZGL.Auth.Sample2。
这个库只是较为粗略的授权认证,与更丰富的需求请自行下载源码修改~
有问题要讨论,可以在俱乐部里面找到我。
深圳、广州、长沙、上海的群等我都在,嘿嘿嘿,嘿嘿嘿。
ASP.NET Core 3.0 一个 jwt 的轻量角色/用户、单个API控制的授权认证库的更多相关文章
- ASP.NET Core 6.0 添加 JWT 认证和授权
序言 本文将分别介绍 Authentication(认证) 和 Authorization(授权). 并以简单的例子在 ASP.NET Core 6.0 的 WebAPI 中分别实现这两个功能. 相关 ...
- asp.net core 2.0 web api基于JWT自定义策略授权
JWT(json web token)是一种基于json的身份验证机制,流程如下: 通过登录,来获取Token,再在之后每次请求的Header中追加Authorization为Token的凭据,服务端 ...
- ASP.NET Core 1.0 入门——Application Startup
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
- [译]ASP.NET Core 2.0 机密配置项
问题 如何在ASP.NET Core 2.0中保存机密配置项(不用将其暴露给源代码管理器)? 答案 创建一个ASP.NET Core 2.0空项目,在项目节点上点击右键,并点击菜单项 - 管理用户机密 ...
- ASP.NET Core 1.0 入门——了解一个空项目
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
- 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(1)
最近使用vscode比较多. 学习了一下如何在mac上使用vscode开发asp.netcore项目. 这里是我写的关于vscode的一篇文章: https://www.cnblogs.com/cgz ...
- 用VSCode开发一个asp.net core2.0+angular5项目(5): Angular5+asp.net core 2.0 web api文件上传
第一部分: http://www.cnblogs.com/cgzl/p/8478993.html 第二部分: http://www.cnblogs.com/cgzl/p/8481825.html 第三 ...
- Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架
Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...
- ASP.NET Core WebAPI中使用JWT Bearer认证和授权
目录 为什么是 JWT Bearer 什么是 JWT JWT 的优缺点 在 WebAPI 中使用 JWT 认证 刷新 Token 使用授权 简单授权 基于固定角色的授权 基于策略的授权 自定义策略授权 ...
随机推荐
- [VB.NET Tips]程序的启动和终止
当执行一个VB.NET应用程序时,CLR会把IL翻译成x86指令,并且寻找一个名为Main的方法. 并从该方法开始执行程序.Main方法也称为程序的"入口"(entry point ...
- 暑期——第五周总结(Web连接hbase数据库)
所花时间:7天 代码行:1000(python)+250(java) 博客量:1篇 了解到知识点 : 在尝试使用hbase当作数据库时,林子雨老师教程中有完整代码关于使用hbase,我就像当然认为只需 ...
- 基于操作系统原理的Linux 的用户管理
一.实验目的 1.掌握为root用户修改密码的方法. 2.掌握创建新用户的方法. 3.掌握用户组的管理方法. 4.掌握为用户授权的方法. 二.实验内容 1.Linux的用户管理 (1)创建新用户创建新 ...
- DeleteFolder
import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; /*** * @author ...
- windows如何利用计划任务自动关机?
第一步打开控制面板,然后选择计划任务,打开它 选择创建基本任务 输入任务名称,描述,选择下一步 根据需要选择,我这里选择的是每天,然后选择下一步 选择任务开始时间,然后选择下一步 选择启动程序,然后选 ...
- 【ADO.NET基础-GridView】GridView的编辑、更新、取消、删除以及相关基础操作代码
代码都是基础操作,后续功能还会更新,如有问题欢迎提出和提问....... 前台代码: <asp:GridView ID=" OnRowDataBound="GridView1 ...
- 【ADO.NET基础-Session】Session的基本应用
在服务端存储状态的对象:Session和Application 在客户端存储状态的对象:Cookie 1.Session:每个独立的浏览器都会创建一个独立的Session,不是一台电脑一个Sessio ...
- .Net Core 商城微服务项目系列(七):使用消息队列(RabbitMQ)实现服务异步通信
RabbitMQ是什么,怎么使用我就不介绍了,大家可以到园子里搜一下教程.本篇的重点在于实现服务与服务之间的异步通信. 首先说一下为什么要使用消息队列来实现服务通信:1.提高接口并发能力. 2.保证 ...
- Windows定时备份Mysql数据库
1.新建批处理文件bat(随意命名:如auto_backup_mysql_data.bat) 2.在批处理文件里添加如下命令 %1 mshta vbscript:createobject(" ...
- Mysql高手系列 - 第18篇:mysql流程控制语句详解(高手进阶)
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第18篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...