.NetCore 使用cookie进行身份认证_izhaorui的博客-程序员ITS301_.netcore cookie

技术标签: cookie  .NetCore  

我们在使用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();
}

 services.AddMvc(options =>
  {
        options.Filters.Add(typeof(UserAuthorizeAttribute));//全局注册用户授权认证
    });

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

/// <summary>
/// 用于定义请求管道中的中间件 http
/// </summary>
/// <param name="app"></param>
/// <param name="env"></param>
// 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

/// <summary>
/// 实现cookie认证授权校验
/// 参考地址:https://www.cnblogs.com/OpenCoder/p/8341843.html
/// </summary>
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);
    }
}

/// <summary>
///因为我使用的是全局注册UserAuthorizeAttribute ,所以这里创建一个不需要授权认证的方法
/// 不需要验证
/// </summary>
public class SkipUserAuthorizeAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        base.OnActionExecuting(context);
    }
}

4.注销

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

   return View("Index");
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_33341938/article/details/90914199

智能推荐

采集方式汇集(sqoop、spark、flume、logstash、filebeat)_CesarChoy的博客-程序员ITS301_sqoop和spark

前文: 数据仓库中ods层一般使用外部表,textfile格式在遇到文本数据时会有分隔符问题,一般默认采用 \001作为分隔符,也可采用parquet作为存储格式,但也会引进数据类型转换的问题。一、Mysql导数据导Hive1.1 建表create external table if not exists ods.ods_stu( `id` int comment '主键Id', `name` string comment '名称',`addtime` stri...

linux系统各种日志存储路径和详细介绍_高尔夫golf的博客-程序员ITS301

Linux常见的日志文件详述如下1、/var/log/boot.log(自检过程)2、/var/log/cron (crontab守护进程crond所派生的子进程的动作)3、/var/log/maillog (发送到系统或从系统发出的电子邮件的活动)4、/var/log/syslog (它只记录警告信息,常常是系统出问题的信息,所以更应该关注该文件)要让系统生成syslog日志

0基础如何自学软件编程开发_梦魇java的博客-程序员ITS301_软件开发编程自学

0基础如何自学软件编程开发?学习软件编程首先需要选择一门编程语言,如C或JAVA语言,作为基础编程语言学习,掌握语言的逻辑,学习语法,其实编程实质上就是思路的运用,编程思路有了再想学习其他的编程语言就会变得顺风顺水。软件编程开发,对于现在的学生来讲到底有多重要呢?现在是互联网快速发展的时期,在几年前谁都没有想到人们在手机上就可以完成衣食住行等所有的活动,互联网也在慢慢的改变着未来一代人。互联网广泛覆盖了我们的生活,真正实现了“远在天边,近在眼前”, 在我们的生活工作中都有互联网存在的身影,随着IT行业的越

在linux下写STM32应用程序,在linux下最简单的STM32gcc程序.docx_扔东西瓜皮的博客-程序员ITS301

在linux下最简单的STM32gcc程序在linux下最简单的STM32 gcc程序,需要三个文件分别为main.c makefile和stm32-linux.ld:main.c:int main(void){return 0;}makefile:TARGET = mainOBJS = main.oCC = arm-none-eabi-gccLD = arm-none-eabi-ldOBJCP ...

2-web服务器原理与nodejs搭建_~怎么回事啊~的博客-程序员ITS301

1 web服务器 浏览器像Chrome不允许直接调用本地的JavaScript程序,所以只能把程序从服务器下载到本地,然后在本地运行javascript程序。 首先APPLICATION是我们自己开发的一个javascript程序,输出给V8引擎,主要对javascript进行一些解析工作,解析完了之后生成一个二进制代码,再加上nodejs本身自己的一些API,解析后的二进制去调用Nodejs的API,调用之后,nodejs还会调用一个叫LIBUV的事件处理库...

1040. 有几个PAT(25)--Python_up中的小猿类的博客-程序员ITS301_python 有几个pat

开始的时候最后三个测试点一直超时,然后借鉴了网上大佬的思路,立马过,跪拜大佬的博string = input()list = list(string)list.reverse()count_T = 0 count_AT = 0count_PAT = 0for num in list: if 'T' == num: count_T += 1 elif 'A' == n

随便推点

让Vivado和ISE共用modelsim_小何的芯像石头的博客-程序员ITS301_ise和vivado共用modelsim

让Vivado和ISE共用modelsim起因是这样的,最近新买了块硬盘,在跟老硬盘对拷的时候,不小心把目标磁盘和源磁盘调转了,导致环境全无了。。为此趁着环境还干净,解决一下这个问题.文章目录让Vivado和ISE共用modelsim安装和破解避雷编译仿真库ISE编译仿真库vivado编译仿真库合并Modelsim.iniISE,vivado调用modelsim结语安装和破解这里涉及到三个软件的安装和破解,我的安装版本是:vivado2017.4ISE14.7Modelsim10.4资源

【RFC2780 互联网协议和相关头部中值的 IANA 分配指南】(翻译)_羊羊洒洒_Blog的博客-程序员ITS301

原文https://datatracker.ietf.org/doc/html/rfc2780IANA Allocation Guidelines For Values In the Internet Protocol and Related Headers 互联网协议和相关头部中值的 IANA 分配指南本文为 IANA 为 IPv4、IPv6、ICMP、UDP 和 TCP 协议头部中的字段分配参数提供了指导。1. 简介多年来,互联网号码分配机构 (IANA) (www.iana.org)...

使用redis的scan指令详解_Danny_idea的博客-程序员ITS301

在生产环境中使用了keys指令之后容易导致出现短时间内的请求堵塞,这种情况在高并发环境中是比较致命的存在,因此需要尽可能地避免这种情况发生。常用的查询某些key的指令:scanjedis使用方式:public List&lt;String&gt; scanAll(String cursor, String pattern, Integer limit) { try (Jedis jedis = iRedisFactory.getConnection()) { List&lt

计算机的设备驱动程序在哪里查看,什么是驱动程序?如何查看电脑的驱动程序?看下面的文章就明白了..._摄影师-谷雨的博客-程序员ITS301

电脑上除了操作系统是非常重要的,还有一部分也是非常重要的,那就是电脑的驱动程序。驱动程序即添加到操作系统中的一小块代码,其中包含有关硬件设备的信息,有了此信息,计算机就可以与设备进行通信。驱动程序是硬件厂商根据操作系统编写的配置文件,可以说没有驱动程序,计算机中的硬件就无法工作。操作系统不同,硬件的驱动程序也不同,各个硬件厂商为了保证硬件的兼容性及增强硬件的功能,会不断的升级驱动程序。驱动程序是硬...

头歌JAVA数据结构答案_嵌入一下?的博客-程序员ITS301_package step1; /** * created by zengpeng on 2018/2

头歌JAVA数据结构答案一、Java数据结构-循环链表的设计与实现第1关 单循环链表的实现—链表的添加、遍历package step1;/** * Created by sykus on 2018/1/15. */public class MyCircleLinkedList { private Node head;//头结点, 不存数据 private Node tail;//尾结点, 指向链表的最后一个节点 private int size; publi

CentOS6.8 使用 fdisk 命令 手动硬盘分区 手动挂载_走向运维的老男孩的博客-程序员ITS301_centos手动分区

初装Linux,使用安装引导界面进行分区,当再增加一块硬盘时,需要手动分区,使用命令 fdisk 进行手动分区。

推荐文章

热门文章

相关标签