asp.net core策略授权

在《asp.net core认证与授权》中讲解了固定和自定义角色授权系统权限,其实我们还可以通过其他方式来授权,比如可以通过角色组,用户名,生日等,但这些主要取决于ClaimTypes,其实我们也可以自定义键值来授权,这些统一叫策略授权,其中更强大的是,我们可以自定义授权Handler来达到灵活授权,下面一一展开。

注意:下面的代码只是部分代码,完整代码参照:https://github.com/axzxs2001/Asp.NetCoreExperiment/tree/master/Asp.NetCoreExperiment/%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86/PolicyPrivilegeManagement

首先看基于角色组,或用户名,或基于ClaimType或自定义键值等授权策略,这些都是通过Services.AddAuthorization添加,并且是AuthorizationOptions来AddPolicy,这里策略的名称统一用RequireClaim来命名,不同的请求的策略名称各不相同,如用户名时就用policy.RequireUserName(),同时,在登录时,验证成功后,要添加相应的Claim到ClaimsIdentity中:

Startup.cs

public void ConfigureServices(IServiceCollection services)

        {

            services.AddMvc();

            services.AddAuthorization(options =>

            {

//基于角色组的策略

                options.AddPolicy("RequireClaim", policy => policy.RequireRole("admin", "system"));

                //基于用户名

                //options.AddPolicy("RequireClaim", policy => policy.RequireUserName("桂素伟"));

                //基于ClaimType

                //options.AddPolicy("RequireClaim", policy => policy.RequireClaim(ClaimTypes.Country,"中国"));

                //自定义值

                // options.AddPolicy("RequireClaim", policy => policy.RequireClaim("date","2017-09-02"));                

            }).AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>{

                options.LoginPath = new PathString("/login");

                options.AccessDeniedPath = new PathString("/denied");

            }); 

        }

HomeController.cs 

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc;

using PolicyPrivilegeManagement.Models;

using Microsoft.AspNetCore.Authorization;

using Microsoft.AspNetCore.Authentication;

using Microsoft.AspNetCore.Authentication.Cookies;

using System.Security.Claims;


namespace PolicyPrivilegeManagement.Controllers

{

    [Authorize(Policy = "RequireClaim")]

    public class HomeController : Controller

    {       

        public IActionResult Index()

        {

            return View();

        }


        public IActionResult About()

        {

            ViewData["Message"] = "Your application description page.";

            return View();

        }

        

        public IActionResult Contact()

        {

            ViewData["Message"] = "Your contact page.";

            return View();

        }


        public IActionResult Error()

        {

            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });

        }

        [AllowAnonymous]

        [HttpGet("login")]

        public IActionResult Login(string returnUrl = null)

        {

            TempData["returnUrl"] = returnUrl;

            return View();

        }

        [AllowAnonymous]

        [HttpPost("login")]

        public async Task<IActionResult> Login(string userName, string password, string returnUrl = null)

        {

            var list = new List<dynamic> {

                new { UserName = "gsw", Password = "111111", Role = "admin",Name="桂素伟",Country="中国",Date="2017-09-02",BirthDay="1979-06-22"},

                new { UserName = "aaa", Password = "222222", Role = "system",Name="测试A" ,Country="美国",Date="2017-09-03",BirthDay="1999-06-22"}

            };

            var user = list.SingleOrDefault(s => s.UserName == userName && s.Password == password);

            if (user != null)

            {

                //用户标识

                var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);

                identity.AddClaim(new Claim(ClaimTypes.Sid, userName));

                identity.AddClaim(new Claim(ClaimTypes.Name, user.Name));

                identity.AddClaim(new Claim(ClaimTypes.Role, user.Role));

                identity.AddClaim(new Claim(ClaimTypes.Country, user.Country));

                identity.AddClaim(new Claim("date", user.Date));


                await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity));

                if (returnUrl == null)

                {

                    returnUrl = TempData["returnUrl"]?.ToString();

                }

                if (returnUrl != null)

                {

                    return Redirect(returnUrl);

                }

                else

                {

                    return RedirectToAction(nameof(HomeController.Index), "Home");

                }

            }

            else

            {

                const string badUserNameOrPasswordMessage = "用户名或密码错误!";

                return BadRequest(badUserNameOrPasswordMessage);

            }

        }

        [HttpGet("logout")]

        public async Task<IActionResult> Logout()

        {

            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

            return RedirectToAction("Index", "Home");

        }

        [AllowAnonymous]

        [HttpGet("denied")]

        public IActionResult Denied()

        {

            return View();

        }

    }

}

上面的授权策略都相对简单,单一,使用场景也很有限,就和固定角色授权如出一辙,其实可以用更好的来例用授权,那就是自定义授权Handler,我们在《asp.net core认证与授权》一文中,是通过中间件来达到自定义解色的,现在我们换个思路,通过自定义授权Handler来实现。

首先定义一个UserPermission,即用户权限实体类

/// <summary>

    /// 用户权限

    /// </summary>

    public class UserPermission

    {

        /// <summary>

        /// 用户名

        /// </summary>

        public string UserName

        { get; set; }

        /// <summary>

        /// 请求Url

        /// </summary>

        public string Url

        { get; set; }

    }


接下来定义一个PermissionRequirement,为请求条件实体类


/// <summary>

    /// 必要参数类

    /// </summary>

    public class PermissionRequirement : IAuthorizationRequirement

    {

        /// <summary>

        /// 用户权限集合

        /// </summary>

        public  List<UserPermission> UserPermissions { get;private set; }

        /// <summary>

        /// 无权限action

        /// </summary>

        public string DeniedAction { get; set; }

        /// <summary>

        /// 构造

        /// </summary>

        /// <param name="deniedAction">无权限action</param>

        /// <param name="userPermissions">用户权限集合</param>

        public PermissionRequirement(string deniedAction, List<UserPermission> userPermissions)

        {

            DeniedAction = deniedAction;

            UserPermissions = userPermissions;

        }

    }


再定义自定义授权Hanlder,我们命名为PermissionHandler,此类必需继承AuthorizationHandler<T>,只用实现public virtual Task HandleAsync(AuthorizationHandlerContext context),些方法是用户请求时验证是否授权的主方法,所以实现与自定义角色中间件的Invoke很相似。

using Microsoft.AspNetCore.Authorization;

using System.Collections.Generic;

using System.Linq;

using System.Security.Claims;

using System.Threading.Tasks;


namespace PolicyPrivilegeManagement.Models

{

    /// <summary>

    /// 权限授权Handler

    /// </summary>

    public class PermissionHandler : AuthorizationHandler<PermissionRequirement>

    {

        /// <summary>

        /// 用户权限

        /// </summary>

        public List<UserPermission> UserPermissions { get; set; }


        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)

        {

            //赋值用户权限

            UserPermissions = requirement.UserPermissions;

            //从AuthorizationHandlerContext转成HttpContext,以便取出表求信息

            var httpContext = (context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext).HttpContext;

            //请求Url

            var questUrl = httpContext.Request.Path.Value.ToLower();

            //是否经过验证

            var isAuthenticated = httpContext.User.Identity.IsAuthenticated;

            if (isAuthenticated)

            {

                if (UserPermissions.GroupBy(g => g.Url).Where(w => w.Key.ToLower() == questUrl).Count() > 0)

                {

                    //用户名

                    var userName = httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Sid).Value;

                    if (UserPermissions.Where(w => w.UserName == userName && w.Url.ToLower() == questUrl).Count() > 0)

                    {

                        context.Succeed(requirement);

                    }

                    else

                    {

                        //无权限跳转到拒绝页面

                        httpContext.Response.Redirect("/denied");

                    }

                }

                else

                {

                    context.Succeed(requirement);

                }

            }

            return Task.CompletedTask;

        }

    }

}

此次的Startup.cs的ConfigureServices发生了变化,如下

public void ConfigureServices(IServiceCollection services)

        {

            services.AddMvc();

            services.AddAuthorization(options =>

            {  

                 //自定义Requirement,userPermission可从数据库中获得

                var userPermission= new List<UserPermission> {

                              new UserPermission {  Url="/", UserName="gsw"},

                              new UserPermission {  Url="/home/permissionadd", UserName="gsw"},

                              new UserPermission {  Url="/", UserName="aaa"},

                              new UserPermission {  Url="/home/contact", UserName="aaa"}

                          };


                options.AddPolicy("Permission",

                          policy => policy.Requirements.Add(new PermissionRequirement("/denied", userPermission)));


            }).AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>{

                options.LoginPath = new PathString("/login");

                options.AccessDeniedPath = new PathString("/denied");


            });

            //注入授权Handler

            services.AddSingleton<IAuthorizationHandler, PermissionHandler>();

        }

HomeController中代码如下:


using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc;

using PolicyPrivilegeManagement.Models;

using Microsoft.AspNetCore.Authorization;

using Microsoft.AspNetCore.Authentication;

using Microsoft.AspNetCore.Authentication.Cookies;

using System.Security.Claims;


namespace PolicyPrivilegeManagement.Controllers

{

    [Authorize(Policy = "Permission")]   

    public class HomeController : Controller

    {

        PermissionHandler _permissionHandler;

        public HomeController(IAuthorizationHandler permissionHandler)

        {

            _permissionHandler = permissionHandler as PermissionHandler;

        }

        public IActionResult Index()

        {

            return View();

        }


        public IActionResult PermissionAdd()

        {           

            return View();

        }


        [HttpPost("addpermission")]

        public IActionResult AddPermission(string url,string userName)

        {       

            //添加权限

            _permissionHandler.UserPermissions.Add(new UserPermission { Url = url, UserName = userName });

            return Content("添加成功");

        }

        

        public IActionResult Contact()

        {

            ViewData["Message"] = "Your contact page.";


            return View();

        }


        public IActionResult Error()

        {

            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });

        }

        [AllowAnonymous]

        [HttpGet("login")]

        public IActionResult Login(string returnUrl = null)

        {

            TempData["returnUrl"] = returnUrl;

            return View();

        }

        [AllowAnonymous]

        [HttpPost("login")]

        public async Task<IActionResult> Login(string userName, string password, string returnUrl = null)

        {

            var list = new List<dynamic> {

                new { UserName = "gsw", Password = "111111", Role = "admin",Name="桂素伟",Country="中国",Date="2017-09-02",BirthDay="1979-06-22"},

                new { UserName = "aaa", Password = "222222", Role = "system",Name="测试A" ,Country="美国",Date="2017-09-03",BirthDay="1999-06-22"}

            };

            var user = list.SingleOrDefault(s => s.UserName == userName && s.Password == password);

            if (user != null)

            {

                //用户标识

                var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);

                identity.AddClaim(new Claim(ClaimTypes.Sid, userName));

                identity.AddClaim(new Claim(ClaimTypes.Name, user.Name));

                identity.AddClaim(new Claim(ClaimTypes.Role, user.Role));

                identity.AddClaim(new Claim(ClaimTypes.Country, user.Country));

                identity.AddClaim(new Claim("date", user.Date));


                await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity));

                if (returnUrl == null)

                {

                    returnUrl = TempData["returnUrl"]?.ToString();

                }

                if (returnUrl != null)

                {

                    return Redirect(returnUrl);

                }

                else

                {

                    return RedirectToAction(nameof(HomeController.Index), "Home");

                }

            }

            else

            {

                const string badUserNameOrPasswordMessage = "用户名或密码错误!";

                return BadRequest(badUserNameOrPasswordMessage);

            }

        }

        [HttpGet("logout")]

        public async Task<IActionResult> Logout()

        {

            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

            return RedirectToAction("Index", "Home");

        }

        [AllowAnonymous]

        [HttpGet("denied")]

        public IActionResult Denied()

        {

            return View();

        }

    }

}

本例设计是当用户gsw密码111111登录时,是不能访问/home/contact的,刚登录时访该action是不成功的,这里我们在/home/addpermission中添加一个Action名称:/home/contact,用户名:gsw的信息,此时再访问/home/contact,会发现是可以访问的,这是因为我们热更新了PermissionHandler中的用户权限集合,用户的权限得到了扩展和变化。

其实用中间件能达到灵活权限的设置,用自定义授权Handler也可以,接下来比较一下两种做法的优劣:


中间件

自定义授权Handler

用户权限集合

静态对象

实体化对象

热更新时

用中间件名称.用户权限集合更新

因为在Startup.cs中,PermissionHandler是依赖注放的,可以在热更新的构造中获取并操作

性能方面

每个action请求都会触发Invock方法,标记[AllowAnonymous]特性的Action也会触发

只有标记[Authorize]特性的Action会触发该方法,标记[AllowAnonymous]特性的Action不会触发,性能更优化


相关文章: 

  • .NET Core 2.0 正式发布信息汇总

  • .NET Standard 2.0 特性介绍和使用指南

  • .NET Core 2.0 的dll实时更新、https、依赖包变更问题及解决

  • .NET Core 2.0 特性介绍和使用指南

  • Entity Framework Core 2.0 新特性

  • 体验 PHP under .NET Core

  • .NET Core 2.0使用NLog

  • 升级项目到.NET Core 2.0,在Linux上安装Docker,并成功部署

  • 解决Visual Studio For Mac Restore失败的问题

  • ASP.NET Core 2.0 特性介绍和使用指南

  • .Net Core下通过Proxy 模式 使用 WCF

  • .NET Core 2.0 开源Office组件 NPOI

  • ASP.NET Core Razor页面 vs MVC

  • Razor Page–Asp.Net Core 2.0新功能  Razor Page介绍

  • MySql 使用 EF Core 2.0 CodeFirst、DbFirst、数据库迁移(Migration)介绍及示例

  • .NET Core 2.0迁移技巧之web.config配置文件

  • asp.net core MVC 过滤器之ExceptionFilter过滤器(一)

  • ASP.NET Core 使用Cookie验证身份

  • ASP.NET Core MVC – Tag Helpers 介绍

  • ASP.NET Core MVC – Caching Tag Helpers

  • ASP.NET Core MVC – Form Tag Helpers

  • ASP.NET Core MVC – 自定义 Tag Helpers

  • ASP.NET Core MVC – Tag Helper 组件

  • ASP.Net Core Razor 页面路由

  • 粗略使用.NetCore2.0自带授权登陆Authorize

原文地址:http://www.cnblogs.com/axzxs2001/p/7482777.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323741.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Safari浏览器不支持let声明的解决方式

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年1月7日16:19:38,前几天用publiccms改了个网站&#xff0c;因为客户那边各种机型都有&#xff08;各PC端的分辨率也都不一样&#xff09;&#xff0c;所以导致页面呈现的效…

Executor 与 ExecutorService 和 Executors 傻傻分不清

转载自 Executor 与 ExecutorService 和 Executors 傻傻分不清 java.util.concurrent.Executor, java.util.concurrent.ExecutorService, java.util.concurrent. Executors 这三者均是 Java Executor 框架的一部分&#xff0c;用来提供线程池的功能。因为创建和管理线程非常心…

ASP.NET Core 2.0 自定义 _ViewStart 和 _ViewImports 的目录位置

在 ASP.NET Core 里扩展 Razor 查找视图目录不是什么新鲜和困难的事情&#xff0c;但 _ViewStart 和 _ViewImports 这2个视图比较特殊&#xff0c;如果想让 Razor 在我们指定的目录中查找它们&#xff0c;则需要耗费一点额外的精力。本文将提供一种方法做到这一点。注意&#x…

Safari浏览器不支持……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂前言现在是2022年1月7日16:19:38,前几天用publiccms改了个网站&#xff0c;因为客户那边各种机型都有&#xff08;各PC端的分辨率也都不一样&#xff09;&#xff0c;所以导致页面呈现的效果…

开源分享 Unity3d客户端与C#分布式服务端游戏框架

很久之前&#xff0c;在博客园写了一篇文章&#xff0c;《分布式网游server的一些想法语言和平台的选择》&#xff0c;当时就有了用C#做网游服务端的想法。写了个Unity3d客户端分布式服务端框架&#xff0c;最近发布了1.0版本&#xff0c;取名ET框架。ET框架的目标就是简化客户…

freemarker中遇到null报错的处理方法

错误分析 今天遇到了这样的个问题&#xff0c;就是在获取分类的父id的时候发现如果是父级分类&#xff0c;则回去父id就会报错。 直接导致了后面的样式失败。 解决办法&#xff1a; 给添加了个默认值0&#xff0c;就可以了&#xff0c;代码如下&#xff1a; var cate_pare…

IDEA的debug方法头坑

一、现象复现 web程序跑起来很卡顿&#xff0c;十几分钟都跑步起来&#xff0c;而且页面刷新十几秒都没有反应。 三月 23, 2019 11:58:22 上午 com.mchange.v2.log.MLog <clinit> 信息: MLog clients using java 1.4 standard logging. 三月 23, 2019 11:58:22 上午 co…

ASP.NET Core MVC I\/O编程模型

1.1. I/O编程模型浅析 服务器端编程经常需要构造高性能的IO模型&#xff0c;常见的IO模型有四种&#xff1a; &#xff08;1&#xff09;同步阻塞IO&#xff08;Blocking IO&#xff09;&#xff1a;即传统的IO模型。 &#xff08;2&#xff09;同步非阻塞IO&#xff08;Non…

几天没写代码,就……

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是2022年2月1日21:07:37&#xff0c;今天是农历2022年的第一天&#xff0c;祝大家虎年大吉&#xff0c;新的一年里身体健康&#xff0c;事业有成&#xff01;&#xff01;&#…

深入浅出 Java CMS 学习笔记

转载自 深入浅出 Java CMS 学习笔记 引子 带着问题去学习一个东西&#xff0c;才会有目标感&#xff0c;我先把一直以来自己对CMS的一些疑惑罗列了下&#xff0c;希望这篇学习笔记能解决掉这些疑惑&#xff0c;希望也能对你有所帮助。 1、 CMS出现的初衷、背景和目的&#x…

vue利用级联选择器实现全国省市区乡村五级菜单联动

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。”现在是&#xff1a;2022年2月13日20:09:27今天分享一个五级级联地址的组件的使用吧。前言接到这样的一个需求&#xff1a;需要根据地址查询列表信息&#xff0c;地址可以分别按照省、市…

业务库负载翻了百倍,我做了什么来拯救MySQL架构

转载自 业务库负载翻了百倍&#xff0c;我做了什么来拯救MySQL架构 作者介绍 杨建荣&#xff0c;竞技世界资深DBA&#xff0c;前搜狐畅游数据库专家&#xff0c;Oracle ACE&#xff0c;YEP成员。拥有近十年数据库开发和运维经验&#xff0c;目前专注于开源技术、运维自动化和…

ASP.NET Core 运行原理解剖[4]:进入HttpContext的世界

本系列文章从源码分析的角度来探索 ASP.NET Core 的运行原理&#xff0c;分为以下几个章节&#xff1a; ASP.NET Core 运行原理解剖[1]:Hosting ASP.NET Core 运行原理解剖[2]:Hosting补充之配置介绍 ASP.NET Core 运行原理解剖[3]:Middleware-请求管道的构成 IHttpContext…

都忘了自己还有一套房子了。。。

​自20年始来&#xff0c;一直租着我的房子。当时疫情刚刚有所好转&#xff0c;我把房子挂在58上&#xff0c;陆陆续续的有好多人问&#xff0c;不过都没有租&#xff0c;一来离我住的地方有点远&#xff0c;过去一次得个把小时的&#xff0c;人家要看房子不能及时过去。二来问…

Visual Studio2017 远程调试 Remote Debugger

前言 大家在使用vs打包后的文件部署到服务器后&#xff0c;有时候我们需要对线网的后台进行调试。但是它不像在VS中。这个时候我们该怎么调试呢&#xff1f; 微软想到了这一点&#xff0c;他们在 VS 中给我们提供了一个功能: Remote Debugger&#xff0c;要远程调试我们就需要…

对于这款APP,我充了个终身VIP!!!

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。”现在是&#xff1a;2022年3月15日00:02:07昨天&#xff0c;无意间知道了一款特牛的APP&#xff0c;看了看&#xff0c;决定充了个终身会员&#xff01;今天&#xff0c;我就简单的对这…

Ubuntu amp;amp; GitLab CI amp;amp; Docker amp;amp; ASP.NETnbs

上一篇&#xff1a;Ubuntu & GitLab CI & Docker & ASP.NET Core 2.0 自动化发布和部署&#xff08;1&#xff09; 服务器版本 Ubuntu 16.04 LTS。 本篇博文目的&#xff1a;项目中添加Dockerfile文件&#xff0c;使用 CI 脚本构建自定义镜像&#xff0c;推送到 …

新版《Windows Sysinternals实战指南》,读书积赞活动

新书《Windows Sysinternals实战指南》即将上市。该本由Sysinternals创始人、Windwos内核技术专家Mark Russinovich 与 Windows专家Aaron Margosis联手编著&#xff0c;详细介绍了Sysinternals每款工具的独到功能&#xff0c;并用较多篇幅深入介绍了如何通过几款重量级工具优化…

Bladex生成Swagger的方法

一、在启动类中添加如下代码&#xff1a;&#xff08;目的是为了打印输出swagger的地址等&#xff09; 注解&#xff1a;Slf4j 实现接口&#xff1a;CommandLineRunner 依赖注入&#xff1a; Autowiredprivate Environment environment;Overridepublic void run(String... str…

了解spark计算模型

简介 在集群背后&#xff0c;有一个非常重要的分布式数据架构&#xff0c;即弹性分布式数据集&#xff08;resilient distributed dataset&#xff0c;RDD&#xff09;&#xff0c;它是逻辑集中的实体&#xff0c;在集群中的多台机器上进行了数据分区。通过对多台机器上不同RDD…