【.NET 8 实战--孢子记账--从单体到微服务】--简易权限--访问权限中间件

server/2024/11/14 8:39:18/

这篇文章我们讲解权限中最关键的地方:访问权限中间件。这个中间件可以帮助我们在请求到达Controller前进行权限验证,并且在不具备权限时通知客户端。

一、需求

我们先来可以下需求:

编号功能描述
1权限验证根据角色和请求的URL来验证是否有访问URL的权限,如果没有则返回401状态码,并告知客户端,反之允许客户端使用URL

二、编写代码

首先,我们需要在ISysRoleUrlServer接口和SysRoleUrlImp实现类中增加IsRoleUseUrl方法,代码如下:

//ISysRoleUrlServer
/// <summary>
/// 角色是否可以访问URL
/// </summary>
/// <param name="roleId"></param>
/// <param name="url"></param>
/// <returns></returns>
bool IsRoleUseUrl(string roleId, string url);//SysRoleUrlImp
/// <summary>
/// 角色是否可以访问URL
/// </summary>
/// <param name="roleId"></param>
/// <param name="url"></param>
/// <returns></returns>
public bool IsRoleUseUrl(string roleId, string url)
{try{return _dbContext.SysRoleUrls.Any(x => x.RoleId == roleId && x.Url.Url == url);}catch (Exception e){throw;}
}

代码很简单,我们就不多讲解了。
然后,我们在项目中新建Middlewares文件夹,在这个文件夹中新建权限验证中间件PermissionsMiddleware,代码如下:

using Microsoft.IdentityModel.Tokens;
using SporeAccounting.Server.Interface;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;namespace SporeAccounting.Middlewares;/// <summary>
/// 权限中间件
/// </summary>
public class PermissionsMiddleware
{private readonly RequestDelegate _next;public PermissionsMiddleware(RequestDelegate next){_next = next;}/// <summary>/// 权限中间件/// </summary>/// <param name="httpContext"></param>/// <param name="sysRoleUrlServer"></param>/// <param name="configuration"></param>public async Task Invoke(HttpContext httpContext, ISysRoleUrlServer sysRoleUrlServer, IConfiguration configuration){//请求的路径string requestPath = httpContext.Request.Path.Value;//如果是登录、注册、找回密码接口,直接放行if (requestPath.Contains("/api/SysUser/Login") ||requestPath.Contains("/api/SysUser/Register") ||requestPath.Contains("/api/SysUser/RetrievePassword")){await _next(httpContext);return;}//解析tokenstring token = httpContext.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();if (token == null){httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;await httpContext.Response.WriteAsync("权限不足:用户无权访问此资源。");}else{// 验证并解析 Tokenvar tokenHandler = new JwtSecurityTokenHandler();var key = Encoding.UTF8.GetBytes(configuration["JWT:IssuerSigningKey"]);try{var claimsPrincipal = tokenHandler.ValidateToken(token, new TokenValidationParameters{ValidateIssuer = true,ValidateAudience = true,ValidIssuer = configuration["JWT:ValidIssuer"],ValidAudience = configuration["JWT:ValidAudience"],IssuerSigningKey = new SymmetricSecurityKey(key),ValidateLifetime = true}, out SecurityToken validatedToken);// 访问 Claimsvar userId = claimsPrincipal.FindFirst(ClaimTypes.NameIdentifier)?.Value;var roleId = claimsPrincipal.FindFirst(ClaimTypes.Role)?.Value;// 在上下文中存储用户信息httpContext.Items["UserId"] = userId;string pathUrlNotParam = string.Join("/", requestPath.Split("/").Take(3));bool isUse = sysRoleUrlServer.IsRoleUseUrl(roleId, pathUrlNotParam);if (isUse){httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;await httpContext.Response.WriteAsync("权限不足:用户无权访问此资源。");return;}await _next(httpContext);}catch (Exception){// Token 无效httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;await httpContext.Response.WriteAsync("无效token");return;}}}
}

在上面的代码中基于 JWT 验证用户身份和角色权限,以确保用户只能访问授权的资源。中间件通过构造函数接收 RequestDelegate 以便在权限验证通过后继续处理请求。在 Invoke 方法中,首先获取请求路径,并检查是否是免验证的接口(如登录、注册、找回密码),对于这些接口直接放行。然后从请求头中提取 Token,并使用 JwtSecurityTokenHandler 验证 Token 的有效性。验证成功后,通过 ClaimsPrincipal 提取用户的 ID 和角色信息,将其存入 HttpContext.Items 中。接着,调用自定义的权限服务 sysRoleUrlServer.IsRoleUseUrl 判断用户角色是否有权访问当前路径。如果权限不足则返回 403 状态码并提示“权限不足”,若 Token 无效则返回 401 状态码提示“无效token”。验证通过后调用 _next(httpContext),将请求传递至下一个中间件或控制器。

最后,我们在Program类中把前面我们编写的中间件注入到项目中:

app.UseMiddleware<PermissionsMiddleware>();

到此,我们的中间件就完成了。

三、总结

这篇文章我们大家一起编写了孢子记账的第一个中间件,后续我们还有更多的中间件编写。


http://www.ppmy.cn/server/141817.html

相关文章

《计算机原理与系统结构》学习系列——存储器(上)

系列文章目录 目录 存储器技术概要存储器层次cache&#xff0c;内存辅存存储器技术SRAM技术DRAM技术闪存磁盘存储器 局部性原理 高速缓存cache访存性能概念命中与缺失访存阻塞的周期数 cache基础&#xff1a;直接映射块号内存地址字段缺失缺失处理和写策略 全相联映射组相连映…

Scala入门基础(17.1)Set集习题

一.选择题 二.实训 图书馆书籍管理系统相关的练习。内容要求&#xff1a; 1.创建一个可变 Set&#xff0c;用于存储图书馆中的书籍信息 &#xff08;假设书籍信息用字符串表示&#xff0c;如“Java编程思想”“Scala实战”等&#xff09; 2.添加两本新的书籍到图书馆集合中&a…

nginx入门教程:alias

在Nginx配置中&#xff0c;alias指令用于指定一个替换位置&#xff0c;即当访问一个特定的location时&#xff0c;Nginx会使用alias指定的路径来替换原始的请求URI&#xff0c;并在这个新路径下查找资源。alias指令对于处理静态文件特别有用&#xff0c;因为它允许将请求映射到…

2024年11月6日Github流行趋势

项目名称&#xff1a;twenty 项目维护者&#xff1a;charlesBochet, lucasbordeau, Weiko, FelixMalfait, bosiraphael 项目介绍&#xff1a;正在构建一个由社区支持的现代版Salesforce替代方案。 项目star数&#xff1a;19,714 项目fork数&#xff1a;2,200 项目名称&#xf…

QQ 小程序已发布,但无法被搜索的解决方案

前言 我的 QQ 小程序在 2024 年 8 月就已经审核通过&#xff0c;上架后却一直无法被搜索到。打开后&#xff0c;再在 QQ 上下拉查看 “最近使用”&#xff0c;发现他出现一下又马上消失。 上线是按正常流程走的&#xff0c;开发、备案、审核&#xff0c;没有任何违规&#xf…

制造企业数字化中台(技术中台、数据中台、业务中台)建设方案

文件是一份关于制造企业数字化中台建设方案的详细报告&#xff0c;由郎丰利1519整理制作。报告内容涵盖了数字化中台的总体解决方案、技术中台&#xff08;A&#xff09;、数据中台&#xff08;B&#xff09;和业务中台&#xff08;C&#xff09;的架构和功能。以下是对PPT内容…

数字逻辑——数制和码制

数制转换 十进制或者二进制在此就不再多说。简单说一下两个进制之间的转化。 十进制转化为二进制&#xff1a; 采用乘基取整法&#xff0c;最后注意不要将结果次序写错了。 将十进制转化为二进制小数&#xff1a; 不同于将余数倒过来&#xff0c;二进制小数相反直接得到。 …

matlab--pdist2(X,Y)使用方法、怎么计算的

1、基本语法&#xff1a; D pdist2(X,Y,Distance,DistParameter) D&#xff1a;使用 Distance 指定的度量返回 X 和 Y 中每对观测值之间的距离 X、Y&#xff1a;两个列数相同的矩阵&#xff0c;X&#xff08;mxn&#xff09;指的是X有m个观测值&#xff0c;n个变量&#xf…