.Net Core Policy 基于策略授权

news/2024/5/20 0:28:38 标签: .netcore

        在ASP.NET Core中,重新设计了一种更加灵活的授权方式:基于策略的授权, 它是授权的核心.在使用基于策略的授权时,首先要定义授权策略,而授权策略本质上就是对Claims的一系列断言。基于角色的授权和基于Scheme的授权,只是一种语法上的便捷,最终都会生成授权策略。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddAuthorization(options =>
    {
        //options.AddPolicy("Administrator", policy => policy.RequireRole("administrator"));
        options.AddPolicy("Administrator", policy => policy.RequireClaim(ClaimTypes.Role, "administrator"));
        
        //options.AddPolicy("Founders", policy => policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5"));
    });
}
[Authorize(Policy = "Administrator")]
public ActionResult<IEnumerable<string>> GetValueByAdminPolicy()
{
    return new string[] { "GetValueByAdminPolicy" };
}

自定义策略授权

        基于策略的授权中有一个很重要的概念是Requirements,每一个Requirement都代表一个授权条件。Requirement需要继承接口IAuthorizationRequirement。
在 ASP.NET Core 中已经内置了一些常用的实现:

AssertionRequirement :使用最原始的断言形式来声明授权策略。
DenyAnonymousAuthorizationRequirement :用于表示禁止匿名用户访问的授权策略,并在AuthorizationOptions中将其设置为默认策略。
ClaimsAuthorizationRequirement :用于表示判断Cliams中是否包含预期的Claims的授权策略。
RolesAuthorizationRequirement :用于表示使用ClaimsPrincipal.IsInRole来判断是否包含预期的Role的授权策略。
NameAuthorizationRequirement:用于表示使用ClaimsPrincipal.Identities.Name来判断是否包含预期的Name的授权策略。
OperationAuthorizationRequirement:用于表示基于操作的授权策略。
        除了OperationAuthorizationRequirement外,都有对应的快捷添加方法,比如RequireClaim,RequireRole,RequireUserName等。当内置的Requirement不能满足需求时,可以定义自己的Requirement。

下面演示自定义策略授权

Startup类配置

 // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthorization(options =>
            {
                options.AddPolicy("Permission", policy => policy.Requirements.Add(new PermissionRequirement()));
            }).AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
            {
                options.LoginPath = new PathString("/api/values/login");
            });
            services.AddTransient<IUserService, UserService>();
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
            services.AddControllers();
        }

 Configure方法添加

app.UseAuthentication();
app.UseAuthorization();

新建类 PermissionRequirement 

  public class PermissionRequirement : IAuthorizationRequirement
    {
    }

新建类 PermissionHandler 

public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
    {
        private readonly IUserService _userService;
        private readonly IHttpContextAccessor _accessor;

        public PermissionHandler(IUserService userService, IHttpContextAccessor accessor)
        {
            _userService = userService;
            _accessor = accessor;
        }

        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
        {
            var httpContext = _accessor.HttpContext;
            var isAuthenticated = httpContext.User.Identity.IsAuthenticated;
            if (isAuthenticated)
            {
                Guid userId;
                if (!Guid.TryParse(httpContext.User.Claims.SingleOrDefault(s => s.Type == "id").Value, out userId))
                {
                    return Task.CompletedTask;
                }
                var functions = _userService.GetFunctionsByUserId(userId);
                var requestUrl = httpContext.Request.Path.Value.ToLower();
                if (functions != null && functions.Count > 0 && functions.Contains(requestUrl))
                {
                    context.Succeed(requirement);
                }
            }
            return Task.CompletedTask;
        }
    }

 添加测试用户数据,项目中需从数据库读取

public static class TestUsers
   {
       public static List<User> Users = new List<User>
       {
           new User{ Id = Guid.NewGuid(), UserName = "Paul", Password = "Paul123", Roles = new List<string>{ "administrator", "api_access" }, Urls = new List<string>{ "/api/values/getadminvalue", "/api/values/getguestvalue" }},
           new User{ Id = Guid.NewGuid(), UserName = "Young", Password = "Young123", Roles = new List<string>{ "api_access" }, Urls = new List<string>{ "/api/values/getguestvalue" }},
           new User{ Id = Guid.NewGuid(), UserName = "Roy", Password = "Roy123", Roles = new List<string>{ "administrator" }, Urls = new List<string>{ "/api/values/getadminvalue" }},
       };
   }


public class User
   {
       public Guid Id { get; set; }
       public string UserName { get; set; }
       public string Password { get; set; }
       public List<string> Roles { get; set; }
       public List<string> Urls { get; set; }
   }

 添加UserService

public interface IUserService
    {
        List<string> GetFunctionsByUserId(Guid id);
    }
 public class UserService : IUserService
    {
        public List<string> GetFunctionsByUserId(Guid id)
        {
            var user = TestUsers.Users.SingleOrDefault(r => r.Id.Equals(id));
            return user?.Urls;
        }
    }

添加api类

[Authorize(Policy = "Permission")]
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        [HttpGet("[action]")]
        public ActionResult<IEnumerable<string>> GetAdminValue()
        {
            return new string[] { "use Policy = Permission" };
        }

        [HttpGet("[action]")]
        public ActionResult<IEnumerable<string>> GetGuestValue()
        {
            return new string[] { "use Policy = Permission" };
        }

      

        [AllowAnonymous]
        [HttpPost("[action]")]
        public async Task<ActionResult<bool>> Login([FromBody]UserDto dto)
        {
            var user = TestUsers.Users.FirstOrDefault(s => s.UserName == dto.UserName && s.Password == dto.Password);
            if (user != null)
            {
                //用户标识
                var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
                identity.AddClaim(new Claim(ClaimTypes.Sid, user.UserName));
                identity.AddClaim(new Claim("id", user.Id.ToString()));


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

                if (dto.ReturnUrl != null)
                {
                    return Redirect(dto.ReturnUrl);
                }
                else
                {
                    return RedirectToAction(nameof(ValuesController.GetAdminValue), "Values");
                }
            }
            else
            {
                const string badUserNameOrPasswordMessage = "用户名或密码错误!";
                return BadRequest(badUserNameOrPasswordMessage);
            }
        }

        public class UserDto
        {
            public string UserName { get; set; }
            public string Password { get; set; }
            public string ReturnUrl { get; set; }
        }
    }

        然后我们用Paul用户可以访问所有的接口,Young只能访问getguestvalue接口,Roy只能访问getadminvalue接口。


http://www.niftyadmin.cn/n/5354761.html

相关文章

Rust中的Anyhow库实践:轻松处理错误与自定义Error类型

一、anyhow库的基本使用 anyhow库提供了一个便捷的Error类型——anyhow::Error&#xff0c;它是一个trait对象&#xff0c;可以容纳任何实现了std::error::Error trait的类型。这意味着你可以方便地将各种不同类型的错误包裹进一个统一的错误类型中&#xff1a; use anyhow::…

Vite+Vue3+TS 引入使用Cesium.js

申请 Cesium Token 进入Cesium 注册账号 cesium 离谱的是 E宝 (Epic) 居然可以快捷登录&#xff1f;&#xff01; 登录后点击导航栏的 Access Token 再右侧即可看到默认Token 安装&引入 # Cesium pnpm pnpm install cesium# 如果项目同时存在Three.js 需避免使用pnpm T…

大数据 - Hadoop系列《四》- MapReduce(分布式计算引擎)的核心思想

上一篇&#xff1a; 大数据 - Hadoop系列《三》- MapReduce&#xff08;分布式计算引擎&#xff09;概述-CSDN博客 目录 13.1 MapReduce实例进程 13.2 阶段组成 13.4 概述 13.4.1 &#x1f959;Map阶段&#xff08;映射&#xff09; 13.4.2 &#x1f959;Reduce阶段执行过…

通过MediaStore查询image,video,arm,pdf等等文件数据

需要直接查询系统库来获取手机上的全部文件信息&#xff0c;如&#xff1a;图片&#xff0c;视频&#xff0c;音频&#xff0c;pdf文件等等。 直接上代码&#xff0c;获取文件的方法&#xff1a; SuppressLint("Range") public ArrayList<DataBean> getFiles(…

flask+django基于python的网上美食订餐系统_3lyq1

设计旨在提高顾客就餐效率、优化餐厅管理、提高订单准确性和客户的满意度。本系统采用 Python 语言作为开发语言&#xff0c;采用Django框架及其第三方库和第三方工具来进行开发。该方案分为管理员功能模块&#xff0c;商家功能模块以及用户前后功能模块三部分。开发前期根据用…

STM32F407移植OpenHarmony笔记3

接上一篇&#xff0c;搭建完环境&#xff0c;找个DEMO能跑&#xff0c;现在我准备尝试从0开始搬砖。 首先把/device和/vendor之前的代码全删除&#xff0c;这个时候用hb set命令看不到任何项目了。 /device目录是硬件设备目录&#xff0c;包括soc芯片厂商和board板级支持代码…

华为手表应用APP开发:watch系列 GT系列 1.配置调试设备

表开发:GT3(1)配置调试设备 初环境与设备获取手表UUID登录 AppGallery Connect 点击用户与访问初 希望能写一些简单的教程和案例分享给需要的人 鸿蒙可穿戴开发 支持外包开发:xkk9866@yeah.net 环境与设备 系统:window 设备:HUAWEI WATCH 3 Pro 开发工具:DevEco St…

Java面试架构篇【一览众山小】

文章目录 &#x1f6a1; 简介☀️ Spring&#x1f425; 体系结构&#x1f420; 生命周期 &#x1f341; SpringMVC&#x1f330; 执行流程 &#x1f31c; SpringBoot&#x1f30d; 核心组件&#x1f38d; 自动装配&#x1f391; 3.0升级 &#x1f505; spring Cloud Alibaba&am…