目录

说明

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. SpringBoot的一个小彩蛋

    彩蛋这种东西还算比较常见,在电影或者游戏里面我们也遇见过不少.今天就简单介绍一下SpringBoot里面的一个小彩蛋. 玩过SpringBoot的同志都知道,SpringBoot的启动界面是这酱紫的: ...

  2. Day 16 软件管理

    1.RPM基本概述 1.什么是rpm? RPM全称 RPM Package Manager 缩写,由红帽开发用于软件包的安装升级卸载与查询 2.如何获取rpm包 在我们刚开始学习rpm包,建议先使用本 ...

  3. C++基础之string类

    string也是属于顺序容器,但是string类很重要且经常使用,因此在这里单独记录. string的操作总结 string(const char *s,int n);  //用c字符串s初始化,s应 ...

  4. C语言入门-数据类型

    一.C语言的类型 整数:char.short.int.long.longlong 浮点型:float.double.long double 逻辑:bool 指针 自定义类型 类型有何不同 类型名称:i ...

  5. vue知识点整理

    1.对于mvvm的理解 mvvm是model-view-viewModel vue是以数据为驱动的,vue自身将dom和数据进行绑定,一旦创建绑定,dom和数据将保持同步,每当数据发生变化,dom也会 ...

  6. Python学习笔记整理总结【网络编程】【线程/进程/协程/IO多路模型/select/poll/epoll/selector】

    一.socket(单链接) 1.socket:应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socke ...

  7. Shell之Glob和RE的区别

    目录 Shell之Glob和RE的区别 参考 Glob RE Shell之Glob和RE的区别

  8. yii2 rules 规则

    required : 必须值验证属性 [['字段名'],required,'requiredValue'=>'必填值','message'=>'提示信息']; #说明:CRequiredV ...

  9. [Swoole] 在Ubuntu下安装、快速开始

    本文主要讲述在 Ubuntu 下编译安装 Swoole,并根据官方文档给出的demo进行了测试和搬运,包括:TCP服务器.UDP服务器.HTTP服务器.WebSocket服务器.异步客户端.定时器和协 ...

  10. Dubbo和Zookerper的关系

    1.Dubbo的作用 Dubbo是管理中间层的工具,在业务层到数据仓库间有非常多服务的接入和服务提供者需要调度,dubbo提供一个框架解决这个问题.Dubbo基于RPC(Remote Procedur ...