asp.net Core 中AuthorizationHandler 实现自定义授权
前言
ASP.NET Core 中 继承的是AuthorizationHandler ,而ASP.NET Framework 中继承的是AuthorizeAttribute.
它们都是用过重写里面的方法实现过滤请求的。
现在我们实现如何在 ASP.NET Core MVC 实现自定义授权。
关于AuthorizationHandler 详细介绍可以看这里
如何自定义授权
比如我们后台有个博客管理功能,那我们可以新建一个Blog的控制器,比如BlogController
里面有添加,删除,编辑等功能,分别是Add,Delete,Edit
代码如下
public class BlogController : Controller
{
public IActionResult Index()
{
return View();
}
/// <summary>
/// 博客添加页面
/// </summary>
/// <returns></returns>
public IActionResult Add()
{
return View();
}
/// <summary>
/// 博客列表页面
/// </summary>
public IActionResult List()
{
return View();
}
/// <summary>
/// 博客编辑页面
/// </summary>
public IActionResult Edit()
{
return View();
}
}
如果有打印可以起个名字叫 public IActionResult Print()
自定义就是做个控制界面做勾选功能,用户根据自身业务选择。

以此类推,在ASP.NET 框架下默认路由就是Controller和Action,除非你修改默认路由,当然了你修改默认路由你的权限逻辑也得变。
实现过滤器
AuthorizationHandler 参数里面有个IAuthorizationRequirement要我们去填充,根据我们自己业务自己选择定义数据。
public class PermissionRequirement : IAuthorizationRequirement
{
/// <summary>
/// 无权限action
/// </summary>
public string DeniedAction { get; set; } = "/Home/visitDeny"; /// <summary>
/// 认证授权类型
/// </summary>
public string ClaimType { internal get; set; }
/// <summary>
/// 默认登录页面
/// </summary>
public string LoginPath { get; set; } = "/Home/Login";
/// <summary>
/// 过期时间
/// </summary>
public TimeSpan Expiration { get; set; }
/// <summary>
/// 构造
/// </summary>
/// <param name="deniedAction"></param>
/// <param name="claimType"></param>
/// <param name="expiration"></param>
public PermissionRequirement(string deniedAction, string claimType, TimeSpan expiration)
{
ClaimType = claimType;
DeniedAction = deniedAction;
Expiration = expiration;
}
}
第一个参数集合
public class PermissionItem
{
/// <summary>
/// 用户或角色或其他凭据名称
/// </summary>
public virtual string Role { get; set; }
/// <summary>
/// 配置的Controller名称
/// </summary>
public virtual string controllerName { get; set; }
/// <summary>
/// 配置的Action名称
/// </summary>
public virtual string actionName { get; set; }
}
Startup 里面,添加一个授权策略,PermissionRequirement 放进去,然后注入
////权限要求参数
var permissionRequirement = new PermissionRequirement(
"/Home/visitDeny",// 拒绝授权的跳转地址
ClaimTypes.Name,//基于用户名的授权
expiration: TimeSpan.FromSeconds( * )//接口的过期时间
);
#endregion //【授权】
services.AddAuthorization(options =>
{
options.AddPolicy("Permission", policy => policy.Requirements.Add(permissionRequirement));
});
// 注入权限处理器
services.AddTransient<IAuthorizationHandler, PermissionHandler>();
控制器里面加上标示
[Authorize("Permission")]
public class BlogController : Controller
{
}
登录页面授权
[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
if (model.textUser == null)
{
ModelState.AddModelError("", "请输入账号.");
return View(model);
}
if (model.textPassword == null)
{
ModelState.AddModelError("", "请输入密码.");
return View(model);
}
if (model.textUser == "admin" && model.textPassword == "")
{
#region 传统的登录
//只判断是否登录 通过[Authorize] 小项目中只有一个管理员 只要账号和密码对就行
var claimIdentity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
claimIdentity.AddClaim(new Claim(ClaimTypes.Name, model.textUser)); var claimsPrincipal = new ClaimsPrincipal(claimIdentity);
//await HttpContext.SignInAsync(claimsPrincipal);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal);
#endregion //下面代码是演示的,实际项目要从根据用户名或者角色从数据库读取出来 配置到 List<PermissionItem>里面
//这里我用的是用户名判断的,根据自己的业务自己处理
//测试的时候 可以 删除一条记录试试,或者添加一条
List<PermissionItem> lsperm = new List<PermissionItem>();
lsperm.Add(new PermissionItem() { Role = model.textUser, controllerName = "Blog", actionName = "Add" });//添加博客页面的权限
lsperm.Add(new PermissionItem() { Role = model.textUser, controllerName = "Blog", actionName = "Edit" });//编辑博客页面的权限
lsperm.Add(new PermissionItem() { Role = model.textUser, controllerName = "Blog", actionName = "List" });//查看博客页面的权限
string perData = JsonConvert.SerializeObject(lsperm);
await _cacheService.SetStringAsync("perm" + model.textUser, perData);
return RedirectToAction("Index", "Home");
}
}
return View(model);
}
List<PermissionItem> 我用Redis存储的,大家根据实际情况存储。
权限判断
public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
{
public IAuthenticationSchemeProvider Schemes;
readonly IDistributedCache _cacheService;
/// <summary>
/// 构造函数注入
/// </summary>
public PermissionHandler(IAuthenticationSchemeProvider schemes, IDistributedCache cacheService)
{
Schemes = schemes;
_cacheService = cacheService;
} // 重载异步处理程序
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
//从AuthorizationHandlerContext转成HttpContext,以便取出表求信息
AuthorizationFilterContext filterContext = context.Resource as AuthorizationFilterContext;
HttpContext httpContext = filterContext.HttpContext;
AuthenticateResult result = await httpContext.AuthenticateAsync(Schemes.GetDefaultAuthenticateSchemeAsync().Result.Name);
//如果没登录result.Succeeded为false
if (result.Succeeded)
{
httpContext.User = result.Principal;
//当前访问的Controller
string controllerName = filterContext.RouteData.Values["Controller"].ToString();//通过ActionContext类的RouteData属性获取Controller的名称:Home
//当前访问的Action
string actionName = filterContext.RouteData.Values["Action"].ToString();//通过ActionContext类的RouteData属性获取Action的名称:Index
string name = httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Name)?.Value;
string perData = await _cacheService.GetStringAsync("perm" + name);
List<PermissionItem> lst = JsonConvert.DeserializeObject<List<PermissionItem>>(perData);
if (lst.Where(w => w.controllerName == controllerName && w.actionName == actionName).Count() > )
{
//如果在配置的权限表里正常走
context.Succeed(requirement);
}
else
{
//不在权限配置表里 做错误提示
//如果是AJAX请求 (包含了VUE等 的ajax)
string requestType = filterContext.HttpContext.Request.Headers["X-Requested-With"];
if (!string.IsNullOrEmpty(requestType) && requestType.Equals("XMLHttpRequest", StringComparison.CurrentCultureIgnoreCase))
{
//ajax 的错误返回
//filterContext.Result = new StatusCodeResult(499); //自定义错误号 ajax请求错误 可以用来错没有权限判断 也可以不写 用默认的
context.Fail();
}
else
{
//普通页面错误提示 就是跳转一个页面
//httpContext.Response.Redirect("/Home/visitDeny");//第一种方式跳转
filterContext.Result = new RedirectToActionResult("visitDeny", "Home", null);//第二种方式跳转
context.Fail();
}
}
}
else
{
context.Fail();
}
}
}
至此我们实现定义授权判断。实际业务上每个人可以根据自己的情况做处理。
asp.net Core 中AuthorizationHandler 实现自定义授权的更多相关文章
- 第十五节:Asp.Net Core中的各种过滤器(授权、资源、操作、结果、异常)
一. 简介 1. 说明 提到过滤器,通常是指请求处理管道中特定阶段之前或之后的代码,可以处理:授权.响应缓存(对请求管道进行短路,以便返回缓存的响应). 防盗链.本地化国际化等,过滤器用于横向处理业务 ...
- asp.net core中遇到需要自定义数据包解密方法的时候
最近将公司的项目用.netcore重写, 服务的http外部接口部分收发消息是DES加解密的, 那么在asp.net core mvc的action处理之前需要加入解密这个步骤. 我第一想到的是用fi ...
- 从零搭建一个IdentityServer——聊聊Asp.net core中的身份验证与授权
OpenIDConnect是一个身份验证服务,而Oauth2.0是一个授权框架,在前面几篇文章里通过IdentityServer4实现了基于Oauth2.0的客户端证书(Client_Credenti ...
- Asp.Net Core 中IdentityServer4 授权中心之自定义授权模式
一.前言 上一篇我分享了一篇关于 Asp.Net Core 中IdentityServer4 授权中心之应用实战 的文章,其中有不少博友给我提了问题,其中有一个博友问我的一个场景,我给他解答的还不够完 ...
- Asp.Net Core 中IdentityServer4 授权原理及刷新Token的应用
一.前言 上面分享了IdentityServer4 两篇系列文章,核心主题主要是密码授权模式及自定义授权模式,但是仅仅是分享了这两种模式的使用,这篇文章进一步来分享IdentityServer4的授权 ...
- Asp.Net Core 中IdentityServer4 实战之角色授权详解
一.前言 前几篇文章分享了IdentityServer4密码模式的基本授权及自定义授权等方式,最近由于改造一个网关服务,用到了IdentityServer4的授权,改造过程中发现比较适合基于Role角 ...
- ASP.NET Core中显示自定义错误页面-增强版
之前的博文 ASP.NET Core中显示自定义错误页面 中的方法是在项目中硬编码实现的,当有多个项目时,就会造成不同项目之间的重复代码,不可取. 在这篇博文中改用middleware实现,并且放在独 ...
- ASP.NET Core中显示自定义错误页面
在 ASP.NET Core 中,默认情况下当发生500或404错误时,只返回http状态码,不返回任何内容,页面一片空白. 如果在 Startup.cs 的 Configure() 中加上 app. ...
- 如何在ASP.NET Core中自定义Azure Storage File Provider
文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...
随机推荐
- CSS学习笔记二:css 画立体图形
继上一次学了如何去运用css画平面图形,这一次学如何去画正方体,从2D向着3D学习,虽然有点满,但总是一个过程,一点一点积累,然后记录起来. Transfrom3D 在这一次中运用到了一下几种属性: ...
- cnblog 模板 SimpleMemory 个性化设置代码备份
/页面顶部作者名/ blogTitle h1 { font-size: 50px; margin-top: 0px; } /页面简介/ blogTitle h2 { letter-spacing: 1 ...
- 第七章之S5PV210移植到Nandflash
1,之前的操作都是基于SD卡进行运行的,如今在Nandfalsh中运行u-boot.因为s5p_goni.h配置文件没有配置Nand相关文件,所以先配置Nand文件. 在include/configs ...
- PAT1049:Counting Ones
1049. Counting Ones (30) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue The tas ...
- hyper-v 安装Centos及网络配置
新安装的Centos系统默认情况下是不能上网的,需要经过相应的配置:选择对应的虚拟机,点击"虚拟交换机管理器": 设置hyper-v上的网络及分配cpu.内存.磁盘等资源. 安装C ...
- 言简意赅的TIME_WAIT
为什么要有TIME_WAIT? 主动关闭端发送完ACK后等2MSL(最长分节生命期),防止对端没有收到ACK这种情况,重发. 官方点,再官方点...... (1) 可靠地实现TCP全双工连接的终止: ...
- Shiro入门之二 --------基于注解方式的权限控制与Ehcache缓存
一 基于注解方式的权限控制 首先, 在spring配置文件applicationContext.xml中配置自动代理和切面 <!-- 8配置自动代理 --> <bean cl ...
- centos tftp和samba的安装与配置
Tftp服务器的安装于配置 1 安装: 命令:#yum –y install tftp 2 安装完毕之后,将tftp服务器设置为开机启动,方法:(命令)#setup→选择system server→选 ...
- 全方位分析web前端如何进行性能优化
前言: 最近刚刚完成项目,空闲一段时间,想起之前有被问起怎么对前端进行性能优化,自己也是脑中零零散散的总不成体系,现特来总结,欢迎补充指教. 1.整体资源 (1)js.css源码压缩 (2)css文件 ...
- (七)SpringBoot2.0基础篇- application.properties属性文件的解析及获取
默认访问的属性文件为application.properties文件,可在启动项目参数中指定spring.config.location的参数: java -jar myproject.jar --s ...