zoukankan      html  css  js  c++  java
  • .Net Core权限认证基于Cookie的认证&授权.Scheme、Policy扩展

    在身份认证中,如果某个Action需要权限才能访问,最开始的想法就是,哪个Action需要权限才能访问,我们写个特性标注到上面即可,[TypeFilter(typeof(CustomAuthorizeActionFilterAttribute))]

    /// <summary>
     /// 这是一个Action的Filter`  但是用作权限验证
     /// </summary>
     public class CustomAuthorizeActionFilterAttribute : Attribute, IActionFilter
     {
         private ILogger<CustomAuthorizeActionFilterAttribute> _logger = null;
         public CustomAuthorizeActionFilterAttribute(ILogger<CustomAuthorizeActionFilterAttribute> logger)
         {
             this._logger = logger;
         }
    
         public void OnActionExecuting(ActionExecutingContext context)
         {
             //取出Session
             var strUser = context.HttpContext.Session.GetString("CurrentUser");
             if (!string.IsNullOrWhiteSpace(strUser))
             {
                 CurrentUser currentUser = Newtonsoft.Json.JsonConvert.DeserializeObject<CurrentUser>(strUser);
                 _logger.LogDebug($"userName is {currentUser.Name}");
             }
             else
             { 
                 context.Result = new RedirectResult("~/Fourth/Login");
             }
              
         }
         public void OnActionExecuted(ActionExecutedContext context)
         {
             //context.HttpContext.Response.WriteAsync("ActionFilter Executed!");
             Console.WriteLine("ActionFilter Executed!");
             //this._logger.LogDebug("ActionFilter Executed!");
         }
    
     }

    当然了,要先在服务里面使用Session的服务==》services.AddSession();

    但是这样不好。.Net Core框架下,有一个特性Authorize,当我们需要使用的时候,在某个Action上面标注即可

     [Authorize]
     public IActionResult Center()
     {
         return Content("Center");
     }

    我们来运行看一下,会报异常

     因为我们没有使用服务,在.Net Core下面,是默认不启用授权过滤器的。这也是.Net Core框架的一个好处,我们需要的时候才进行使用。框架做的少,更轻。

    下面我们在服务里面使用授权过滤器的服务

    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).
        AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
    o =>
        {
            o.LoginPath = new PathString("/Home/Login");
        });

    再次浏览刚才的页面,这样就会请求到登录页面,会把刚才请求的页面当做一个参数

    当然也要使用app.UseAuthentication();这个中间件。

    在.Net Core里面,保存登录状态,也是通过Cookie的方式。使用ClaimsIdentity与ClaimsPrincipal

    public ActionResult Login(string name, string password)
    {
        this._ilogger.LogDebug($"{name} {password} 登陆系统");
        #region 这里应该是要到数据库中查询验证的
        CurrentUser currentUser = new CurrentUser()
        {
            Id = 123,
            Name = "Bingle",
            Account = "Administrator",
            Password = "123456",
            Email = "415473422@qq.com",
            LoginTime = DateTime.Now,
            Role = name.Equals("Bingle") ? "Admin" : "User"
        };
        #endregion
    
        #region cookie
        {
            ////就很像一个CurrentUser,转成一个claimIdentity
            var claimIdentity = new ClaimsIdentity("Cookie");
            claimIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, currentUser.Id.ToString()));
            claimIdentity.AddClaim(new Claim(ClaimTypes.Name, currentUser.Name));
            claimIdentity.AddClaim(new Claim(ClaimTypes.Email, currentUser.Email));
            claimIdentity.AddClaim(new Claim(ClaimTypes.Role, currentUser.Role));
            claimIdentity.AddClaim(new Claim(ClaimTypes.Sid, currentUser.Id.ToString()));
            var claimsPrincipal = new ClaimsPrincipal(claimIdentity);
            base.HttpContext.SignInAsync(claimsPrincipal).Wait();//不就是写到cookie
        }
        #endregion
    
        return View();
    }

    再次进行登录,我们就可以看到这样一个Cookie

     在这之后,我们再去访问Genter页面,发现还是和之前返回的结果一样,还是访问不到。这是为什么呢?是因为我们在Action上面打的标签[Authorize],什么都没给,我们做下修改

     [Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
     public IActionResult Center()
     {
         return Content("Center");
     }

    现在我们再次进行访问,发现就可以访问成功了

     

    通过User.FindFirstValue(ClaimTypes.Sid);这种方式,可以获取到我们存入的值。

    Scheme、Policy扩展

    Scheme

    #region 设置自己的schema的handler 
     services.AddAuthenticationCore(options => options.AddScheme<MyHandler>("myScheme", "demo myScheme"));
     #endregion
     #region  Schame 验证
    
     services.AddAuthentication(options =>
     {
         options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;// "Richard";//  
     })
     .AddCookie(options =>
     {
         options.LoginPath = new PathString("/Fourth/Login");// 这里指定如果验证不通过就跳转到这个页面中去
         options.ClaimsIssuer = "Cookie";
     });

    MyHandler类:

    /// <summary>
    /// 自定义的handler
    /// 通常会提供一个统一的认证中心,负责证书的颁发及销毁(登入和登出),而其它服务只用来验证证书,并用不到SingIn/SingOut。
    /// </summary>
    public class MyHandler : IAuthenticationHandler, IAuthenticationSignInHandler, IAuthenticationSignOutHandler
    {
        public AuthenticationScheme Scheme { get; private set; }
        protected HttpContext Context { get; private set; }
    
        public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
        {
            Scheme = scheme;
            Context = context;
            return Task.CompletedTask;
        }
    
        /// <summary>
        /// 认证
        /// </summary>
        /// <returns></returns>
        public async Task<AuthenticateResult> AuthenticateAsync()
        {
            var cookie = Context.Request.Cookies["myCookie"];
            if (string.IsNullOrEmpty(cookie))
            {
               return  AuthenticateResult.NoResult();
            }
            return AuthenticateResult.Success(this.Deserialize(cookie));
        }
    
        /// <summary>
        /// 没有登录 要求 登录 
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        public Task ChallengeAsync(AuthenticationProperties properties)
        {
            Context.Response.Redirect("/login");
            return Task.CompletedTask;
        }
    
        /// <summary>
        /// 没权限
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        public Task ForbidAsync(AuthenticationProperties properties)
        {
            Context.Response.StatusCode = 403;
            return Task.CompletedTask;
        }
    
        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="user"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
        {
            var ticket = new AuthenticationTicket(user, properties, Scheme.Name);
            Context.Response.Cookies.Append("myCookie", this.Serialize(ticket));
            return Task.CompletedTask;
        }
    
        /// <summary>
        /// 退出
        /// </summary>
        /// <param name="properties"></param>
        /// <returns></returns>
        public Task SignOutAsync(AuthenticationProperties properties)
        {
            Context.Response.Cookies.Delete("myCookie");
            return Task.CompletedTask;
        }
        private AuthenticationTicket Deserialize(string content)
        {
            byte[] byteTicket = System.Text.Encoding.Default.GetBytes(content);
            return TicketSerializer.Default.Deserialize(byteTicket);
        }
    
        private string Serialize(AuthenticationTicket ticket)
        {
    
            //需要引入  Microsoft.AspNetCore.Authentication
    
            byte[] byteTicket = TicketSerializer.Default.Serialize(ticket);
            return Encoding.Default.GetString(byteTicket);
        }
    }

    Policy

     #region 支持 policy 认证授权的服务  
    
     // 指定通过策略验证的策略列
     services.AddSingleton<IAuthorizationHandler, AdvancedRequirement>();
    
     services.AddAuthorization(options =>
     {
         //AdvancedRequirement可以理解为一个别名
         options.AddPolicy("AdvancedRequirement", policy =>
         {
             policy.AddRequirements(new NameAuthorizationRequirement("1"));
         });
     }).AddAuthentication(options =>
     {
         options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
     })
     .AddCookie(options =>
     {
         options.LoginPath = new PathString("/Fourth/Login");
         options.ClaimsIssuer = "Cookie";
     });
    
     #endregion

    AdvancedRequirement类:

     /// <summary>
     /// Policy 的策略 或者是规则
     /// </summary>
     public class AdvancedRequirement : AuthorizationHandler<NameAuthorizationRequirement>, IAuthorizationRequirement
     { 
         protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, NameAuthorizationRequirement requirement)
         {
             // 这里可以把用户信息获取到以后通过数据库进行验证
             // 这里就可以做一个规则验证
             // 也可以通过配置文件来验证
             if (context.User != null && context.User.HasClaim(c => c.Type == ClaimTypes.Sid))
             {
                 string sid = context.User.FindFirst(c => c.Type == ClaimTypes.Sid).Value;
                 if (!sid.Equals(requirement.RequiredName))
                 {
                     context.Succeed(requirement);
                 }
             }
    
             return Task.CompletedTask;
         }
     }

    还需要在Configure方法中对中间件进行使用

    app.UseSession();
    app.UseCookiePolicy(); //
    app.UseAuthentication(); // 标识在当前系统中使用这个权限认证

     总结:

      在.Net Framwork环境授权一般来说是这个样子的,在登录的时候写入Session,在需要控制权限的方法上标机一个权限特性,实现在方法执行前对Session进行判断,如果有Session,就有权限。但是这种方式比较局限。

      .Net Core下的权限认证,来自于AuthenticationHttpContextExtensions扩展。

      6大方法,可以自行扩展这6个方法:需要自定义一个handler,handler需要继承实现IAuthenticationHandler,IAuthenticationSignInHandler,IAuthenticationSignOutHandler。分别实现6个方法,需要制定在Core中使用。services.AddAuthenticationCore(options => options.AddScheme<MyHandler>("myScheme", "demo myScheme"));

      如果使用了Sechme验证,验证不通过的时候,就默认跳转到Account/Login?ReturnUrl=......。权限验证来自于IAuthentizeData:AuthenticationSchemes Policy Roles。权限验证支持Action、控制器、全局三种注册方式。

  • 相关阅读:
    mysql----SELECT names/zh
    Java开源博客My-Blog(SpringBoot+Docker)系列文章
    shell脚本中字符串的常见操作及"command not found"报错处理(附源码)
    运行shell脚本时报错"[[ : not found"解决方法
    使用ajax方法实现form表单的提交
    Spring+SpringMVC+MyBatis整合优化篇
    Spring+SpringMVC+MyBatis整合基础篇
    Spring+SpringMVC+MyBatis整合(easyUI、AdminLte3)
    Java开源博客My-Blog之docker容器组件化修改
    短信发送接口被恶意访问的网络攻击事件(四)完结篇--搭建WAF清理战场
  • 原文地址:https://www.cnblogs.com/taotaozhuanyong/p/11594931.html
Copyright © 2011-2022 走看看