目录

说明

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控制的授权认证库的更多相关文章

  1. ASP.NET Core 6.0 添加 JWT 认证和授权

    序言 本文将分别介绍 Authentication(认证) 和 Authorization(授权). 并以简单的例子在 ASP.NET Core 6.0 的 WebAPI 中分别实现这两个功能. 相关 ...

  2. asp.net core 2.0 web api基于JWT自定义策略授权

    JWT(json web token)是一种基于json的身份验证机制,流程如下: 通过登录,来获取Token,再在之后每次请求的Header中追加Authorization为Token的凭据,服务端 ...

  3. ASP.NET Core 1.0 入门——Application Startup

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  4. [译]ASP.NET Core 2.0 机密配置项

    问题 如何在ASP.NET Core 2.0中保存机密配置项(不用将其暴露给源代码管理器)? 答案 创建一个ASP.NET Core 2.0空项目,在项目节点上点击右键,并点击菜单项 - 管理用户机密 ...

  5. ASP.NET Core 1.0 入门——了解一个空项目

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  6. 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(1)

    最近使用vscode比较多. 学习了一下如何在mac上使用vscode开发asp.netcore项目. 这里是我写的关于vscode的一篇文章: https://www.cnblogs.com/cgz ...

  7. 用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 第三 ...

  8. 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 ...

  9. ASP.NET Core WebAPI中使用JWT Bearer认证和授权

    目录 为什么是 JWT Bearer 什么是 JWT JWT 的优缺点 在 WebAPI 中使用 JWT 认证 刷新 Token 使用授权 简单授权 基于固定角色的授权 基于策略的授权 自定义策略授权 ...

随机推荐

  1. springcloud config配置读取优先级

    情景描述 最近在修复Eureka的静态页面加载不出的缺陷时,最终发现是远程GIT仓库将静态资源访问方式配置给禁用了(spring.resources.add-mappings=false).虽然最后直 ...

  2. .Net Reactor混淆导致匿名类处理出现的问题处理分析

    .Net Reactor 是一款比较不错的混淆工具,比VS自带的那个好用很多,一直以来也陪伴着我们的成长,虽然没有完美的混淆工具,不过也算还是不错的,至少能在一定程度上对DLL进行一定的保护处理. 不 ...

  3. 还在用SVN的人,要不要学Git?

    还在用SVN的人,要不要学Git? 提出这个问题,是因为很多小伙伴还不会使用Git. 在Git之前,是SVN的天下. SVN诞生于2001年,由于较为先进的管理方式而迅速取代了CVS. 很多80后小伙 ...

  4. 12.Django基础十之Form和ModelForm组件

    一 Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户 ...

  5. 深入探究js中的隐式变量声明

    前两天遇到的问题,经过很多网友的深刻讨论,终于有一个相对可以解释的通的逻辑了,然后我仔细研究了一下相关的点,顺带研究了一下js中的隐式变量. 以下文章中提到的隐式变量都是指没有用var,let,con ...

  6. Spring Cloud 初认识

    Spring Cloud是一个继承了众多开源的框架,其利用了Springboot开发的便利性来实现分布式服务功能,是一套开放.易部署.易维护的分布式开发工具包,而且有成熟的社区且社区活跃度很高.Spr ...

  7. 第二篇:php开发工具

    倍,这里为您介绍一些常用的工具. PHP IDE PHP IDE也不少,主要从几个方面进行筛选: 跨平台(能够同时在windows,mac或者ubuntu上面运行) 版本控制(SVN,GIT) 文件历 ...

  8. Salesforce学习之路-developer篇(三)利用Visualforce Page实现页面的动态刷新案例学习

    Visualforce是一个Web开发框架,允许开发人员构建可以在Lightning平台上本地托管的自定义用户界面.其框架包含:前端的界面设计,使用的类似于HTML的标记语言:以及后端的控制器,使用类 ...

  9. NAT网络下tcp_tw_recycle参数引起的故障

    记录一次阿里云服务器故障排查思路 公司网络是nat 环境 问题: 同一个服务有两台服务器 172.19.19.252 172.19.19.187 两台服务器 要连node5 发现172.19.19.2 ...

  10. 队列 & 栈---概述

    队列 是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表.进行插入操作的端称为队尾,进行删除操作 ...