.NET Core中的认证管理解析

0x00 问题来源

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

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。

 

登录:

注册:

注销:

具体示例可以到:

https://github.com/durow/NetCoreStudy

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

0x05 写在最后

第一次接触Web应用,很多概念都不是很了解。就拿Cookie认证用户来说,我之前的只知道通过Cookie识别用户,一直以为是收到Cookie后再从数据库或缓存中查出相应的权限信息。不过看了自带的Cookie中间件代码后才知道认证信息是直接存在Cookie中的,这样只要解密后反序列化就可以了。Identity这个程序集涉及了很多其它程序集(Security、HttpAbstraction等等),看得我很晕,最后总算搞明白了一些,很多细节也没去深究,文中内容有的基于代码,有的基于个人理解,有错误希望大家嘴下留情。

原文地址:http://www.cnblogs.com/durow/p/5783089.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/328740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

散列算法,Remal使用散列算法

一、散列算法 散列算法让其保证不可逆,安全。这里举一个例子sh1的摘要算法。上代码 /*** 散列算法* author Administrator*/ public class HashRsaUtil {/*** 加密方式*/public static final String SHA1"SHA-1";/*** 加密次数*/public static final In…

简化得最没道理的6个汉字,让人大跌眼镜

文章来源于网络,侵删!!! 1、“進”被简化为“进”,“進”字是让人“越走越佳”。 简化字却把它改成了“进”字,让你越走越走到“井”里去了,井底之蛙自生自灭。 2、“廠”被简化为“厂”字&…

c++

#include <iostream> #include<cmath> using namespace std; int main() { int x; double a; double b; while(cin >> x ){//注意while处理多个case for(int i 0 ;i < x ; i ){ cin>>a; …

在docker中运行ASP.NET Core Web API应用程序

本文是一篇指导快速演练的文章&#xff0c;将介绍在docker中运行一个ASP.NET Core Web API应用程序的基本步骤&#xff0c;在介绍的过程中&#xff0c;也会对docker的使用进行一些简单的描述。对于.NET Core以及docker的基本概念&#xff0c;网上已经有很多文章对其进行介绍了&…

谈谈 Java 的克隆

转载自 谈谈 Java 的克隆为什么要克隆对象 做开发很少用到克隆的。我能想得到的是用于调用方法时作为参数传递&#xff0c;为了保证方法调用前后对象的内部结构不被破坏&#xff0c;可以克隆一个对象作为参数传递。 使类具有克隆能力 有人可能注意到 Object 类中有一个 native…

android启调支付宝

网上找了一个可以起吊支付宝的appdemo &#xff0c;它集成了服务器端&#xff0c;我先将其分离为app和服务器端&#xff0c;保证app在接收参数后可以启调支付宝 &#xff08;保证app这边是正确的 不然出错都不知道是服务器出错还是app出错&#xff09;&#xff0c;在 找网上资…

shiro-身份授权流程、案例

一、身份授权流程 首先调用Subject.isPermitted/hasRole接口&#xff0c;委托给SecurityManager.SecurityManager接着会委托给内部组件Authorizer.Authorizer再将其请求委托给我们的Realm去做&#xff0c;Realm才是真正干活的.realm将用户请求的参数封装成权限对象&#xff0c…

对Java的URL类支持的协议进行扩展的方法

转载自 对Java的URL类支持的协议进行扩展的方法JAVA默认提供了对file,ftp,gopher,http,https,jar,mailto,netdoc协议的支持。当我们要利用这些协议来创建应用时&#xff0c;主要会涉及到如下几个类&#xff1a;java.net.URL、java.net.URLConnection、InputStream。URL类默认…

在.Net项目中使用Redis作为缓存服务

最近由于项目需要&#xff0c;在系统缓存服务部分上了redis&#xff0c;终于有机会在实际开发中玩一下&#xff0c;之前都是自己随便看看写写&#xff0c;很零碎也没沉淀下来什么&#xff0c;这次算是一个系统学习和实践过程的总结。 和Redis有关的基础知识 Redis是一个开源的分…

中国的程序员培训是不是有问题?

内容来源于&#xff0c;看最下面的出处&#xff0c;侵删 中国技术开放日的出海团对日本进行了为期一周的访问。笔者随行了头两天&#xff0c;参加Slush Asia大会&#xff0c;并访问了Gungho和Deloitte两家企业。虽然已经在日本生活了四年&#xff0c;但这样的体验却甚少&#x…

后台回调支付宝

https://blog.csdn.net/u012552275/article/details/78320051 网上找了一个可以起吊支付宝的appdemo &#xff0c;它集成了服务器端&#xff0c;我先将其分离为app和服务器端&#xff0c;保证app在接收参数后可以启调支付宝 &#xff08;保证app这边是正确的 不然出错都不知道…

解决高版本SpringBoot整合swagger时启动报错:Failed to start bean ‘documentationPluginsBootstrapper‘ 问题

一、控制台的报错信息 2021-12-29 15:15:04 [main] ERROR org.springframework.boot.SpringApplication - Application run failed org.springframework.context.ApplicationContextException: Failed to start bean documentationPluginsBootstrapper; nested exception is j…

java图片格式转化(例如jpg格式转化png)

转载自 java图片格式转化&#xff08;例如jpg格式转化png&#xff09; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Scanner;import javax.imageio.*; public class FormatConversion {public static final Str…

微软开源PowerShell并支持Linux

建议在Wifi 环境下观看视频 class"video_iframe" data-vidtype"1" style" z-index:1; " height"375" width"500" frameborder"0" data-src"https://v.qq.com/iframe/preview.html?vidv0322g7kd3f&width…

招银网络科技笔试

记录一下 招银网络笔试 2017年09月11日 14:32:53 阅读数&#xff1a;2450 Part1. 30道单选 涉及Java&#xff0c;C&#xff0c;多线程&#xff0c;算法&#xff0c;数据结构&#xff0c;CPU&#xff0c;NP问题&#xff0c;SQL语句&#xff0c;IP地址转换&#xff0c;行测。…

mybatisGenerator逆向工程

一、在pom文件中导入依赖和generator插件 <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency&…

2016最佳温情小说:雨还在下....

作者 | 李德霞 来源 | 小小说选刊 哗&#xff0c;一道闪电&#xff1b;轰&#xff0c;一个响雷。 暴雨倾盆&#xff0c;天地间浑沌一片…… 老大扑腾腾坐起来&#xff0c;心也跟着扑腾腾地跳。老大拉亮灯&#xff0c;推推身边的媳妇。媳妇一骨碌爬起来&#xff0c;咋&#xf…

java 中 image 和 byte[] 相互转换

转载自 java 中 image 和 byte[] 相互转换只需要一个存储了图片信息的二进制串&#xff08;byte[]&#xff09; 然后&#xff0c;这样&#xff1a; InputStream buffin new ByteArrayInputStream(/*二进制串*/, /*起始位置*/,/*二进制串长度*/)); BufferedImage img ImageIO…

招银网络

记录一下 招银网络笔试 2017年09月11日 14:32:53 阅读数&#xff1a;2451 Part1. 30道单选 涉及Java&#xff0c;C&#xff0c;多线程&#xff0c;算法&#xff0c;数据结构&#xff0c;CPU&#xff0c;NP问题&#xff0c;SQL语句&#xff0c;IP地址转换&#xff0c;行测。…

Java 文件和byte数组转换

转载自 Java 文件和byte数组转换 /** * 获得指定文件的byte数组 */ private byte[] getBytes(String filePath){ byte[] buffer null; try { File file new File(filePath); FileInputStream fis new FileInputStream(file); ByteArrayOutputStream bos new ByteAr…