.net MVC下鉴权认证(二)

上次讲了.net mvc下鉴权认证的传统方法通过过滤器来实现,那进入.net core时代以后,可以通过鉴权中间件来实现,下面就以mvc程序为例来说明下通过中间件如何来实现。

这里的环境使用的是vs2019 + .net core3.1

在startup的ConfigureServices中配置认证

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(op => {
                    op.LoginPath = new PathString("/Login");//登录路径
                    op.AccessDeniedPath = new PathString("/Login/Denied");//无权限地址
                });

然后在Configure中配置中间件,注意要放在app.UseRouting和app.UseEndpoints两者之间才可以

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
            if (env.IsDevelopment()) {
                app.UseDeveloperExceptionPage();
            }
            else {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();//鉴权 是否登录

            app.UseAuthorization();//授权 是否有权限访问此操作

            app.UseEndpoints(endpoints => {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }

然后在要管理权限的控制器或action上进行标记特性[Authorize]就行了,如果不需要进行管理则可以使用[AllowAnonymousAttribute]特性标记就行

    public class HomeController : Controller {
        private readonly ILogger<HomeController> _logger;

        public HomeController(ILogger<HomeController> logger) {
            _logger = logger;
        }
        [Authorize]
        public IActionResult Index() {
            return View();
        }
    }

登陆控制器代码

    public class LoginController : Controller {
        public IActionResult Index() {
            return View();
        }

        public IActionResult DoLogin(string account, string pwd) {
            if (account == "1646" && pwd == "123") {
                var roleList = new List<string>() {
                    "admin",
                    "test"
                };
                //身份用户声明
                var claims = new List<Claim>() {
                    new Claim(ClaimTypes.Name, $"{account}信息"),
                    new Claim("account", account)
                };
                //填充角色
                foreach (var item in roleList) {
                    claims.Add(new Claim(ClaimTypes.Role, item));
                }
                //装载到身份主体中
                ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "UserInfo"));
                //写入到cookie中
                HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal,
                    new AuthenticationProperties {
                        ExpiresUtc = DateTime.Now.AddMinutes(30)//设置过期时间
                    }).Wait();
                //跳转
                return RedirectToAction("Index", "Home");
            }
            else {
                TempData["error"] = "账号或密码不正确";
                return RedirectToAction("Index", "Login");
            }
        }

        public IActionResult Denied() {
            return View();
        }
    }

然后直接访问Home/Index则会报401直接跳转到Login/Index,因为在startup中有进行配置未登陆处理地址为Login/Index.然后通过登录页面执行登录操作后,再次访问Home/Index就可以成功访问了。

角色管理

上面的权限管控只是管控到有登录就ok,如果要进一步进行角色的权限管控我们可以在特性[Authorize(Roles ="admin")] 上面加上roles指定可以授权的角色就行,那么此角色可以访问其他角色就不行了。如果有多个角色可以","分开。也可以写多个特性标记在上面,如下面的代码那么只有admin角色才可以访问。因为上面登录代码中我有加上角色claims.Add(new Claim(ClaimTypes.Role, item));里面包含了admin所以此页面可以访问,如果把这个角色拿掉再来访问此页面就会报403跳转到Login/Denied,因为在startup中有配置无权限的跳转路径。

    public class HomeController : Controller {
        private readonly ILogger<HomeController> _logger;

        public HomeController(ILogger<HomeController> logger) {
            _logger = logger;
        }
        [Authorize(Roles ="admin")]
        public IActionResult Index() {
            return View();
        }
    }

自定义策略授权进阶

可以发现到目前为止我们的角色这些都是,直接在特性中用代码来写的,这种应该只适合一些小的项目,一般项目中我们还是希望能够后台进行配置的。.net core还支持自定义策略授权

1.添加CustomAuthorizatinRequirement.cs这个类实现接口IAuthorizationRequirement,这个IAuthorizationRequirement是个空接口,我们直接实现不用写什么代码。

    public class CustomAuthorizatinRequirement : IAuthorizationRequirement {

    }

2.添加CustomAuthorizationHandler.cs这个认证处理类,这个类需要实现IAuthorizationRequirement这个接口,不过一般我们都是通过继承AuthorizationHandler<T>泛型抽象类来实现。

    public class CustomAuthorizationHandler: AuthorizationHandler<CustomAuthorizatinRequirement> {
        private IHttpContextAccessor _httpContext;
        public CustomAuthorizationHandler(IHttpContextAccessor httpContext) {
            _httpContext = httpContext;
        }

        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomAuthorizatinRequirement requirement) {
            bool flag=false;
            var httpContext = _httpContext.HttpContext;
            RouteEndpoint res = context.Resource as RouteEndpoint;
            if (res != null) {
                if (res.RoutePattern.RequiredValues.Keys.Count() == 2){
                    var action = res.RoutePattern.RequiredValues.ToList().FirstOrDefault(b => b.Key == "action").Value;
                    var ctr = res.RoutePattern.RequiredValues.ToList().FirstOrDefault(b => b.Key == "controller").Value;
                }
            }

            var user = context.User.Claims.FirstOrDefault(b => b.Type == "account").Value;

            if (user == "1646") {
                flag = true;
            }
            if (flag) {
                context.Succeed(requirement);
            }
            return Task.CompletedTask;
        }
    }

3.让自定义策略生效,需要在服务注册services.AddSingleton<IAuthorizationHandler, CustomAuthorizationHandler>();还有策略的注册

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

            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            //自定义认证处理的服务注册
            services.AddSingleton<IAuthorizationHandler, CustomAuthorizationHandler>();
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(op => {
                    op.LoginPath = new PathString("/Login");//登录路径
                    op.AccessDeniedPath = new PathString("/Login/Denied");//无权限地址
                });
            //策略的注册
            services.AddAuthorization(op => {
                op.AddPolicy("policy1", p => {
                    p.AddRequirements(new CustomAuthorizatinRequirement());
                });
            });
        }

然后在控制器上加上

    public class HomeController : Controller {
        private readonly ILogger<HomeController> _logger;

        public HomeController(ILogger<HomeController> logger) {
            _logger = logger;
        }
        [Authorize(Roles ="admin")]
        public IActionResult Index() {
            return View();
        }
        [Authorize(policy: "policy1")]
        public IActionResult Index1() {
            return View();
        }

    }

这样我访问Home/Index1的时候如果未登陆则直接跳转到Login/Index,登陆以后就会通过CustomAuthorizationHandler这个处理类来进行授权判断,这里面的业务逻辑可以自己来实现,里面都可以拿到当前访问的controller和action,以前用户角色等信息,对权限判断都不成问题了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值