热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

NETCore中的认证管理解析

2016-08-1907:152016-08-1907:150x00问题来源在新建.NETCore的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经
 

0x00 问题来源

在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册、登录等很多页面,也可以使用AuthorizeAttribute进行各种权限管理,看起来似乎十分方便。不过生成的代码都替我干了些什么我一团雾水。看了下生成的数据表,功能也挺复杂的。实际上我需要的只是基于用户和角色的认证管理,而且用户资料是使用现有的库,但使用.NET Core自带的认证组件必须要依赖EF,表的结构也很多对不上,所以学习了下自带的认证组件的实现,然后自己写了个认证服务替换了Identity组件,同时COOKIE管理使用自带的COOKIE中间件、可以使用AuthorizeAttribute进行认证。复杂的需求还没遇到,所以就学习到了这里。这篇博客主要讨论最简单情况下的的基于用户和角色的认证。关于.NET Core自带认证组件的一些基本用法,可以参考。

0x01 .NET Core中的认证管理

提到认证管理,首相想到的就是用户的注册、登录、注销以及给用户添加/删除角色等功能。其中用户信息,角色信息等都是保存在数据库中的。所以主要包含数据库操作和登录业务逻辑两部分。在登录业务逻辑层面,.NET Core主要通过三个比较核心的类UserManager、RoleManager、SigninManager进行管理(在Microsoft.AspNetCore.Identity程序集)。其中:

  • UserManager主要负责用户的认证、注册、修改、删除以及与用户相关的角色、令牌、声明等的管理。

  • RoleManager负责角色、角色相关声明的管理。

  • SigninManager负责登录、注销等相关操作。在涉及到用户操作(如登陆时用户验证)会调用UserManager进行操作。

这三个核心类在操作数据库时,使用数据库层面的UserStore、RoleStore进行操作(在Microsoft.AspNetCore.Identity.EntityFrameworkCore程序集)。业务关系如下图所示:

技术分享图片

我们在开发认证相关功能时使用这三个核心类即可满足大多数需求。我们在使用这几个核心类的对象时都是通过依赖注入获取的,那么这些相关的依赖是什么时候注入的呢?在Startup的ConfigureServices方法中有AddIdentity扩展方法,就是在这个方法中添加了需要的所有依赖。

技术分享图片

0x02 登录和注销

了解了Identity组件的整体分工后,再来看一下登录和注销的操作的部分细节。登录和注销过程主要由SigninManager负责,的先来看一下登录的过程:

技术分享图片

登录成功后Response的Header中包含了Set-COOKIE,COOKIE的Key需要和COOKIE中间件中设置的要解密的COOKIE的Key一致,在截图中这个COOKIE的Key是IdentityCOOKIE。设置COOKIE的同时返回302重定向到登录页面。

技术分享图片

重定向到登陆页面时,请求中已经带有设置的Key为IdentityCOOKIE的COOKIE了。

技术分享图片

注销过程比较简单,调用HttpContext.Authentication.SignOutAsync方法即可注销,此时会给HttpContext.Response添加Set-COOKIE,但内容为空。

技术分享图片

0x03 通过COOKIE识别用户

.NET Core中通过COOKIEAuthenticationMiddleware这个中间件识别HttpContext中认证相关的COOKIE,从而添加用户的验证和授权信息。最关键的是ClaimsPrincipal对象,它记录用户的认证和授权信息(除此之外当然也可以包含其它你需求的任意信息),从上面登录过程可以看到,登录成功后用户认证和授权信息保存至ClaimsPrincipal对象(实际上对于这条COOKIE键值对中的认证信息保存为ClaimsIdentity,一个ClaimsPrincipal可以包含多个ClaimsIdentity),然后在HttpContext.Response的Headers中添加Set-COOKIE,Key为COOKIE中间件中指定的COOKIEName,Value就是这个对象加密后的字符串。以后的HttpContext都会带有这个COOKIE,COOKIE中间件会把符合这个COOKIEName的COOKIE取出来,解密并还原为ClaimsPrincipal对象,并把HttpContext.User设置为这个对象。后面MVC中间件在路由到相应Controller和Action的时候就可以根据Authorize特性中指定的认证和角色在HttpContext.User中进行检查,不满足检查则跳转至相应页面。因此需要注意的就是一定要把COOKIE中间件放在MVC中间件之前。

技术分享图片

这里需要特别说一下ClaimsPrincipal。一个ClaimsPrincipal对象中包含了一个或多个ClaimsIdentity对象,一个ClaimsIdentity对象一般来说对应着一个COOKIE中某条键值对(个人理解)。COOKIE中间件和ClaimsIdentity是通过AuthenticationScheme联系起来的。后面我们在写自己的认证服务时,也是把COOKIE中间件的AuthenticationScheme和创建的ClaimsIdentity一致。所以更准确地说是ClaimsIdentity包含了用户认证和权限的声明,而ClaimsPrincipal可以包含多个ClaimsIdentity。当管道中存在多个COOKIE中间件时,通过AuthenticationScheme进行区分。

在ClaimsIdentity中除了AuthenticationScheme外还有两个比较重要的属性,UserType和RoleType,其中UserType指定了用户验证类型,RoleType指定可角色验证类型。意思就是如果我指定了RoleType为”RoleName”,那么在进行角色认证时就会寻找Claims中所有的Type为”RoleName”的值,并检查其中是否包含了Authorize中指定的RoleName。不过.NET Core中自带了ClaimTypes,可以直接使用。例如角色类型就是ClaimTypes.Role。如果添加角色时用的自带的ClaimTypes.Role,那么在创建ClaimsIdentity时就不需要显示指定RoleType了,默认角色认证就是使用ClaimTypes.Role。

关于COOKIE中间件的添加,是通过Startup中Configure方法中的app.UseIdentity扩展方法实现的。这个扩展方法实际上添加了多种COOKIE识别方式。在后面我在写自己的用户认证管理时只用一种。

技术分享图片

0x04 自己写用户认证管理

了解了用户认证的过程,我们可以自己写认证管理来代替Identity组件了,同样分为数据库操作和认证业务逻辑。数据库相关就不多说了,都写到了IdentityRepository类,只有很简单的数据操作。为了方便使用了Dapper,数据库用的Sqlite。程序在启动时会检查数据库表,没有会自动创建空表。

技术分享图片

认证服务也比较简单就都写到了IdentityService类,提供了注册和登录操作,注销太简了直接写在了Action里。为了方便没有提供角色管理页面,如果要测试角色认证功能,需要手动去数据库添加Role,然后在UserRoles中给用户添加Role。

技术分享图片

登录:

技术分享图片

注册:

技术分享图片

注销:

技术分享图片

具体示例可以到:

只是为了测试,逻辑上很多问题,比如用户密码明文存储。重点看过程:)

0x05 写在最后

第一次接触Web应用,很多概念都不是很了解。就拿COOKIE认证用户来说,我之前的只知道通过COOKIE识别用户,一直以为是收到COOKIE后再从数据库或缓存中查出相应的权限信息。不过看了自带的COOKIE中间件代码后才知道认证信息是直接存在COOKIE中的,这样只要解密后反序列化就可以了。

NET Core中的认证管理解析


推荐阅读
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • Webmin远程命令执行漏洞复现及防护方法
    本文介绍了Webmin远程命令执行漏洞CVE-2019-15107的漏洞详情和复现方法,同时提供了防护方法。漏洞存在于Webmin的找回密码页面中,攻击者无需权限即可注入命令并执行任意系统命令。文章还提供了相关参考链接和搭建靶场的步骤。此外,还指出了参考链接中的数据包不准确的问题,并解释了漏洞触发的条件。最后,给出了防护方法以避免受到该漏洞的攻击。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 在project.properties添加#Projecttarget.targetandroid-19android.library.reference.1..Sliding ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
author-avatar
干杯彩妮子
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有