.Net Core AOP之AuthorizeAttribute

[删除(380066935@qq.com或微信通知)]

更好的阅读体验请查看原文:https://www.cnblogs.com/sportsky/p/15940483.html

一、简介

在.net core 中Filter分为以下六大类:

1、AuthorizeAttribute(权限验证)

2、IResourceFilter(资源缓存)

3、IActionFilter(执行方法前后的记录)

4、IResultFilter(结果生成前后扩展)

5、IAlwaysRun(响应结果的补充)

6、IExceptionFilter(异常处理)

二、AuthorizeAttribute(权限验证)

认证授权分为三种,如下:

1、基于角色授权

1.1、配置Startup.cs 类,使用Cookie及角色授权方式访问 —— 修改 ConfigureServices 与 Configure方法

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

            { 
                // ************1、添加鉴权和授权逻辑**************************
                services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
                {
                    options.LoginPath = new PathString("/Login/LoginView"); // 登录地址
                    options.AccessDeniedPath = new PathString("/Login/AccessDenied"); // 无权限访问需要跳转的页面地址
                    options.LogoutPath = new PathString("/Login/LoginOff"); // 登出地址
                    options.ExpireTimeSpan = TimeSpan.FromMinutes(1); // cookie有效时间(这里设置的1分钟有效时间)
                    options.Cookie = new CookieBuilder
                    {
                        // cookie名称,Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")取得是当前环境变量的名称,用户可自定义
                        Name = $"WebUI_{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}" 
                    };
                });
                services.AddAuthorization();
                // **********************************************************
            }
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseRouting();

            // ***************2、鉴权*******************
            app.UseAuthentication();
            // 授权
            app.UseAuthorization();
            
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Login}/{action=LoginView}/{id?}");
            });
        }

 

1.2、使用授权的时候在Action或controller上打上Authorize特性并赋值Role属性,表示该方法只能由Admin的角色访问

public class LoginController : Controller
    {
        // 登录页面
        public IActionResult LoginView()
        {
            return View();
        }

        /// <summary>
        /// 登录方法
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        public async Task<IActionResult> Login()
        {

            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name,"xiaohemiao"),
                new Claim(ClaimTypes.Role,"Admin")
            };
            var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme
                , new ClaimsPrincipal(claimsIdentity)
                , new AuthenticationProperties()
                {
                    ExpiresUtc = DateTime.UtcNow.AddMinutes(1)
                }); 
           
            return Redirect("/Login/Index");
        }

        /// <summary>
        /// 登录成功之后跳转的页面
        /// </summary>
        /// <returns></returns>
        [Authorize(Roles = "Admin")]
        public IActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// 登出
        /// </summary>
        /// <returns></returns>
        public async Task<IActionResult> LoginOff()
        {
            await HttpContext.SignOutAsync();
            return Redirect("/Login/LoginView");
        }

        /// <summary>
        /// 无权限页面
        /// </summary>
        /// <returns></returns>
        public IActionResult AccessDenied()
        {
            return View();
        }

        
    }

 

2、基于声明授权

修改基于标题1的相关代码

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

            { 
                // ************1、添加鉴权和授权逻辑**************************
                services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
                {
                    options.LoginPath = new PathString("/Login/LoginView"); // 登录地址
                    options.AccessDeniedPath = new PathString("/Login/AccessDenied"); // 无权限访问需要跳转的页面地址
                    options.LogoutPath = new PathString("/Login/LoginOff"); // 登出地址
                    options.ExpireTimeSpan = TimeSpan.FromMinutes(1); // cookie有效时间(这里设置的1分钟有效时间)
                    options.Cookie = new CookieBuilder
                    {
                        // cookie名称,Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")取得是当前环境变量的名称,用户可自定义
                        Name = $"WebUI_{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}" 
                    };
                });
                services.AddAuthorization(options => {
                    // 当角色是Admin和SuperAdministrator才可以访问
                    options.AddPolicy("AdministratorOnly", policy => policy.RequireClaim(ClaimTypes.Role, "Admin", "SuperAdministrator"));
                });
                // **********************************************************
            }
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseRouting();

            // ***************2、鉴权*******************
            app.UseAuthentication();
            // 授权
            app.UseAuthorization();
            
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Login}/{action=LoginView}/{id?}");
            });
        }

 

public class LoginController : Controller
    {
        // 登录页面
        public IActionResult LoginView()
        {
            return View();
        }

        /// <summary>
        /// 登录方法
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        public async Task<IActionResult> Login()
        {

            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name,"xiaohemiao"),
                new Claim(ClaimTypes.Role,"Admin")
            };
            var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme
                , new ClaimsPrincipal(claimsIdentity)
                , new AuthenticationProperties()
                {
                    ExpiresUtc = DateTime.UtcNow.AddMinutes(1)
                }); 
           
            return Redirect("/Login/Index");
        }

        /// <summary>
        /// 登录成功之后跳转的页面
        /// </summary>
        /// <returns></returns>
        [Authorize(Policy = "AdministratorOnly")]
        public IActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// 登出
        /// </summary>
        /// <returns></returns>
        public async Task<IActionResult> LoginOff()
        {
            await HttpContext.SignOutAsync();
            return Redirect("/Login/LoginView");
        }

        /// <summary>
        /// 无权限页面
        /// </summary>
        /// <returns></returns>
        public IActionResult AccessDenied()
        {
            return View();
        }

        
    }

 

3、自定义策略授权

3.1、定义权限策略

 

public class PermissionRequirement: IAuthorizationRequirement
    {

    }

 

3.2、再定义个策略处理类

public class RoleAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
    {
        private readonly ILogger<RoleAuthorizationHandler> _logger;
        private readonly IHttpContextAccessor _httpContextAccessor;

        public RoleAuthorizationHandler(ILogger<RoleAuthorizationHandler> logger, IHttpContextAccessor httpContextAccessor)
        {
            _logger = logger;
            this._httpContextAccessor = httpContextAccessor;
        }
        public override Task HandleAsync(AuthorizationHandlerContext context)
        {
            var mvcContext = _httpContextAccessor.HttpContext;
            var user = context.User.FindFirst(ClaimTypes.Role)?.Value;
           
            if (mvcContext.User.Identity.IsAuthenticated)
            {
                var routes = mvcContext.GetRouteData();
                var controller = routes.Values["controller"]?.ToString()?.ToLower();
                var action = routes.Values["action"]?.ToString()?.ToLower();

                var activeTime = mvcContext.User.FindFirst(ClaimTypes.Expired);
                // 是否登录超时
                if (activeTime == null || Convert.ToDateTime(activeTime.Value) < DateTime.Now)
                {
                    // 登录超时自动跳转到登录页面
                    mvcContext.Response.Redirect("/Login/LoginView");
                    context.Succeed(context.Requirements.FirstOrDefault());
                    return Task.CompletedTask;
                }

                var hasRole = mvcContext.User.HasClaim(c => c.Type == ClaimTypes.Role);
                if (!hasRole)
                {
                    //用户未在系统添加,即使登录成功,也要提示没有权限
                    context.Fail();
                    return Task.CompletedTask;
                }

                var menuPaths = AuthorizationMenuPath(user);
                string route = $"/{controller}";
               
                var actionRoute = $"/{controller}/{(routes.Values["action"] ?? "Index")}".ToLower();
                if (menuPaths.Any(m => m.ToLower().Contains($"/{controller}/")) || menuPaths.Any(m => m.ToLower() == route) || menuPaths.Any(m => m.ToLower() == actionRoute))
                    context.Succeed(context.Requirements.FirstOrDefault());
                else context.Fail();//会默认跳转 accessdenied视图
                
            }
            else
                context.Fail();

            return Task.CompletedTask;
        }
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
        {
            throw new NotImplementedException();
        }


        /// <summary>
        /// 权限动态缓存类 临时替代数据库
        /// </summary>
        /// <param name="roleName">角色名称</param>
        /// <returns></returns>
        private List<string> AuthorizationMenuPath(string roleName)
        {
            switch (roleName)
            {
                case "Admin":
                    return new List<string>() { "/Login/Index" };
                default:
                    return new List<string>() { "/Login/Index" };
            }
            
        }
    }

 

3.3、修改 ConfigureServices 与 Configure方法

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

            {

                // ************3、注入自定义策略**************************
                services.AddSingleton<IAuthorizationHandler, RoleAuthorizationHandler>();
                // ************1、添加鉴权和授权逻辑**************************
                services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
                {
                    options.LoginPath = new PathString("/Login/LoginView"); // 登录地址
                    options.AccessDeniedPath = new PathString("/Login/AccessDenied"); // 无权限访问需要跳转的页面地址
                    options.LogoutPath = new PathString("/Login/LoginOff"); // 登出地址
                    options.ExpireTimeSpan = TimeSpan.FromMinutes(1); // cookie有效时间(这里设置的1分钟有效时间)
                    options.Cookie = new CookieBuilder
                    {
                        // cookie名称,Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")取得是当前环境变量的名称,用户可自定义
                        Name = $"WebUI_{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}" 
                    };
                });
                services.AddAuthorization(options =>
                {
                    options.AddPolicy("RolePolicy", policy =>policy.Requirements.Add(new PermissionRequirement()));
                   
                });

                services.AddHttpContextAccessor();
                // **********************************************************
            }
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseRouting();

            // ***************2、鉴权*******************
            app.UseAuthentication();
            // 授权
            app.UseAuthorization();
            
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Login}/{action=LoginView}/{id?}");
            });
        }

3.4 、controller代码逻辑

public class LoginController : Controller
    {
        // 登录页面
        public IActionResult LoginView()
        {
            return View();
        }

        /// <summary>
        /// 登录方法
        /// </summary>
        /// <returns></returns>
        [AllowAnonymous]
        public async Task<IActionResult> Login()
        {

            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name,"xiaohemiao"),
                new Claim(ClaimTypes.Role,"Admin"),
                new Claim(ClaimTypes.Expired,DateTime.Now.AddMinutes(1).ToString("yyyy-MM-dd HH:mm:ss"))
                
            };
            var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme
                , new ClaimsPrincipal(claimsIdentity)
                , new AuthenticationProperties()
                {
                    
                }); 
           
            return Redirect("/Login/Index");
        }

        /// <summary>
        /// 登录成功之后跳转的页面
        /// </summary>
        /// <returns></returns>
        [Authorize(Policy = "RolePolicy")]
        public IActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// 登出
        /// </summary>
        /// <returns></returns>
        public async Task<IActionResult> LoginOff()
        {
            await HttpContext.SignOutAsync();
            return Redirect("/Login/LoginView");
        }

        /// <summary>
        /// 无权限页面
        /// </summary>
        /// <returns></returns>
        public IActionResult AccessDenied()
        {
            return View();
        }

        
    }