.NetCore 使用cookie进行身份认证

我们在使用ASP.NET的时候一定都用过FormsAuthentication做登录用户的身份认证,FormsAuthentication的核心就是Cookie,ASP.NET会将用户名存储在Cookie中。

现在到了ASP.NET CORE的时代,但是ASP.NET CORE中没有FormsAuthentication这个东西,那么怎么做身份认证呢?答案是ASP.NET CORE已经为我们内置了Cookie身份认证的功能,而且使用起来非常方便,注意本文是基于ASP.NET CORE 2.2版本来阐述Cookie认证方式的

1.ASP.NET CORE 框架中启用Cookie身份认证功能

要在ASP.NET CORE中使用Cookie身份认证,第一步就是在项目中的Startup.cs中启用Cookie身份认证中间件。Startup.cs 中的 ConfigureServices 方法中使用AddAuthentication注册cookie认证服务。具体代码如下:

public void ConfigureServices(IServiceCollection services)
{
    ......
    //注册Cookie认证服务
    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
}

然后在Startup.cs中的Configure方法中使用app. 启用cookie认证中间件(注意:app.UseAuthentication();要放在 app.UseMvc()前面)

/// 
/// 用于定义请求管道中的中间件 http
/// 
/// 
/// 
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifetime)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }
    //2019-5-26 add 注册用户身份验证
    //app.UseAuthentication会启用Authentication中间件,该中间件会根据当前Http请求中的Cookie信息来设置HttpContext.User属性(后面会用到),所以只有在app.UseAuthentication方法之后注册的中间件才能够从HttpContext.User中读取到值,这也是为什么上面强调app.UseAuthentication方法一定要放在下面的app.UseMvc方法前面,因为只有这样ASP.NET Core的MVC中间件中才能读取到HttpContext.User的值。
    app.UseAuthentication();

   //mvc路由中间件
    app.UseMvc(routes =>
    {
        //默认路由
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

2.用户登录

// 登录处理
public IActionResult Login(string username, string password)
{
    ApiResult apiResult = new ApiResult();

    if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
    {
        apiResult.Code = 1;
        apiResult.Message = "请输入用户名或密码";
        return OutputJson(apiResult);
    }

    //Member member = UserService.Login(username, password);
    t_user member = UserService.User_Login(username, password);

    if (member != null)
    {
        apiResult.OnSuccess(apiResult);

        //下面的变量claims是Claim类型的数组,Claim是string类型的键值对,所以claims数组中可以存储任意个和用户有关的信息,
        //不过要注意这些信息都是加密后存储在客户端浏览器cookie中的,所以最好不要存储太多特别敏感的信息,这里我们只存储了用户名到claims数组,
        //表示当前登录的用户是谁
        //var claims = new[] { new Claim("username", username) };

        var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
        identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, member.Uid.ToString()));
        identity.AddClaim(new Claim(ClaimTypes.Name, member.Screen_name));

        ClaimsPrincipal principal = new ClaimsPrincipal(identity);

        Task.Run(async () =>
        {
            //登录用户,相当于ASP.NET中的FormsAuthentication.SetAuthCookie
            //await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);

            //可以使用HttpContext.SignInAsync方法的重载来定义持久化cookie存储用户认证信息,例如下面的代码就定义了用户登录后60分钟内cookie都会保留在客户端计算机硬盘上,
            //即便用户关闭了浏览器,60分钟内再次访问站点仍然是处于登录状态,除非调用Logout方法注销登录。
            //注意其中的AllowRefresh属性,如果AllowRefresh为true,表示如果用户登录后在超过50%的ExpiresUtc时间间隔内又访问了站点,就延长用户的登录时间(其实就是延长cookie在客户端计算机硬盘上的保留时间),
            //例如本例中我们下面设置了ExpiresUtc属性为60分钟后,那么当用户登录后在大于30分钟且小于60分钟内访问了站点,那么就将用户登录状态再延长到当前时间后的60分钟。但是用户在登录后的30分钟内访问站点是不会延长登录时间的,
            //因为ASP.NET Core有个硬性要求,是用户在超过50%的ExpiresUtc时间间隔内又访问了站点,才延长用户的登录时间。
            //如果AllowRefresh为false,表示用户登录后60分钟内不管有没有访问站点,只要60分钟到了,立马就处于非登录状态(不延长cookie在客户端计算机硬盘上的保留时间,60分钟到了客户端计算机就自动删除cookie)

            await HttpContext.SignInAsync(
            CookieAuthenticationDefaults.AuthenticationScheme,//这里要注意的是HttpContext.SignInAsync(AuthenticationType,…) 所设置的Scheme一定要与前面的配置一样,这样对应的登录授权才会生效。
            principal,
            new AuthenticationProperties()
            {
                IsPersistent = true,
                ExpiresUtc = DateTimeOffset.UtcNow.AddHours(1),//有效时间
                AllowRefresh = true
            });
        }).Wait();
    }

    return OutputJson(apiResult);
}

3.读取cookie

/// 
/// 实现cookie认证授权校验
/// 参考地址:https://www.cnblogs.com/OpenCoder/p/8341843.html
/// 
public class UserAuthorizeAttribute : ActionFilterAttribute
{
    static Logger logger = LogManager.GetCurrentClassLogger();

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        bool IsAuthenticated = false;

        var requestURL = context.HttpContext.Request.Path;

        //如果HttpContext.User.Identity.IsAuthenticated为true,
        //或者HttpContext.User.Claims.Count()大于0表示用户已经登录
        if (context.HttpContext.User.Identity.IsAuthenticated)
        {
            IsAuthenticated = true;
        }


        if (IsAuthenticated)
        {
            //这里通过 HttpContext.User.Claims 可以将我们在Login这个Action中存储到cookie中的所有
            //claims键值对都读出来,比如我们刚才定义的UserName的值admin就在这里读取出来了
            var userName = context.HttpContext.User.FindFirst(ClaimTypes.Name).Value;

            logger.Info($"[{userName}]用户登录校验成功,请求地址[{requestURL}]");
        }
        else
        {
            logger.Info($"没登录访问地址[{requestURL}]");

            context.Result = new RedirectResult("/Home/Login?returnURL=" + requestURL);
            return;
        }
        base.OnActionExecuting(context);
    }
}

/// 
/// 不需要验证
/// 
public class SkipUserAuthorizeAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        base.OnActionExecuting(context);
    }
}

4.注销

/// 
/// 退出登录
/// 如果当前Http请求本来就没有登录用户,那么调用HttpContext.SignOutAsync方法时也不会报错
/// 
/// 
public IActionResult LoginOut()
{
   Task.Run(async () =>
   {
       //注销登录的用户,相当于ASP.NET中的FormsAuthentication.SignOut  
       await HttpContext.SignOutAsync();
   }).Wait();

   return View("Index");
}

你可能感兴趣的:(.NetCore)