.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();cookie

可是这样很差。.Net Core框架下,有一个特性Authorize,当咱们须要使用的时候,在某个Action上面标注便可app

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

咱们来运行看一下,会报异常框架

 

 由于咱们没有使用服务,在.Net Core下面,是默认不启用受权过滤器的。这也是.Net Core框架的一个好处,咱们须要的时候才进行使用。框架作的少,更轻。async

下面咱们在服务里面使用受权过滤器的服务ide

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

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

 

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

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

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();
}

再次进行登陆,咱们就能够看到这样一个Cookiecode

 

 在这以后,咱们再去访问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、控制器、全局三种注册方式。

相关文章
相关标签/搜索