上篇文章介绍了
IdentityServer4的源码分析的内容,让我们知道了IdentityServer4的一些运行原理,这篇将介绍如何使用dapper来持久化Identityserver4,让我们对IdentityServer4理解更透彻,并优化下数据请求,减少不必要的开销。.netcore项目实战交流群(637326624),有兴趣的朋友可以在群里交流讨论。
一、数据如何实现持久化
在进行数据持久化之前,我们要了解Ids4是如何实现持久化的呢?Ids4默认是使用内存实现的IClientStore、IResourceStore、IPersistedGrantStore三个接口,对应的分别是InMemoryClientStore、InMemoryResourcesStore、InMemoryPersistedGrantStore三个方法,这显然达不到我们持久化的需求,因为都是从内存里提取配置信息,所以我们要做到Ids4配置信息持久化,就需要实现这三个接口,作为优秀的身份认证框架,肯定已经帮我们想到了这点啦,有个EFCore的持久化实现,GitHub地址https://github.com/IdentityServer/IdentityServer4.EntityFramework,是不是万事大吉了呢?拿来直接使用吧,使用肯定是没有问题的,但是我们要分析下实现的方式和数据库结构,便于后续使用dapper来持久化和扩展成任意数据库存储。
下面以IClientStore接口接口为例,讲解下如何实现数据持久化的。他的方法就是通过clientId获取Client记录,乍一看很简单,不管是用内存或数据库都可以很简单实现。
Task<Client> FindClientByIdAsync(string clientId);要看这个接口实际用途,就可以直接查看这个接口被注入到哪些方法中,最简单的方式就是Ctrl+F
,通过查找会发现,Client实体里有很多关联记录也会被用到,因此我们在提取Client信息时需要提取他对应的关联实体,那如果是数据库持久化,那应该怎么提取呢?这里可以参考IdentityServer4.EntityFramework项目,我们执行下客户端授权如下图所示,您会发现能够正确返回结果,但是这里执行了哪些SQL查询呢?
从EFCore实现中可以看出来,就一个简单的客户端查询语句,尽然执行了10次数据库查询操作(可以使用SQL Server Profiler查看详细的SQL语句),这也是为什么使用IdentityServer4获取授权信息时奇慢无比的原因。

这肯定不是实际生产环境中想要的结果,我们希望是尽量一次连接查询到想要的结果。其他2个方法类似,就不一一介绍了,我们需要使用dapper来持久化存储,减少对服务器查询的开销。
特别需要注意的是,在使用refresh_token时,有个有效期的问题,所以需要通过可配置的方式设置定期清除过期的授权信息,实现方式可以通过数据库作业、定时器、后台任务等,使用dapper持久化时也需要实现此方法。
二、使用Dapper持久化
下面就开始搭建Dapper的持久化存储,首先建一个IdentityServer4.Dapper类库项目,来实现自定义的扩展功能,还记得前几篇开发中间件的思路吗?这里再按照设计思路回顾下,首先我们考虑需要注入什么来解决Dapper的使用,通过分析得知需要一个连接字符串和使用哪个数据库,以及配置定时删除过期授权的策略。
新建IdentityServerDapperBuilderExtensions类,实现我们注入的扩展,代码如下。

整体框架基本确认了,现在就需要解决这里用到的几个配置信息和实现。
- DapperStoreOptions需要接收那些参数? 
- 如何使用dapper实现存储的三个接口信息? 
首先我们定义下配置文件,用来接收数据库的连接字符串和配置清理的参数并设置默认值。

如上图所示,这里定义了最基本的配置信息,来满足我们的需求。
下面开始来实现客户端存储,SqlServerClientStore类代码如下。


这里面涉及到几个知识点,第一dapper的高级使用,一次性提取多个数据集,然后逐一赋值,需要注意的是sql查询顺序和赋值顺序需要完全一致。第二是AutoMapper的实体映射,最后封装的一句代码就是_client.ToModel();即可完成,这与这块使用还不是很清楚,可学习相关知识后再看,详细的映射代码如下。


这样就完成了从数据库里提取客户端信息及相关关联表记录,只需要一次连接即可完成,奈斯,达到我们的要求。接着继续实现其他2个接口,下面直接列出2个类的实现代码。
SqlServerResourceStore.cs



使用dapper提取存储数据已经全部实现完,接下来我们需要实现定时清理过期的授权信息。
首先定义一个清理过期数据接口IPersistedGrants,定义如下所示。

现在我们来实现下此接口,详细代码如下。

有个清理的接口和实现,我们需要注入下实现builder.Services.AddTransient<IPersistedGrants, SqlServerPersistedGrants>();,接下来就是开启后端服务来清理过期记录。




是不是实现一个定时任务很简单呢?功能完成别忘了注入实现,现在我们使用dapper持久化的功能基本完成了。
builder.Services.AddSingleton<TokenCleanup>(); builder.Services.AddSingleton<IHostedService, TokenCleanupHost>();三、测试功能应用
在前面客户端授权中,我们增加dapper扩展的实现,来测试功能是否能正常使用,且使用SQL Server Profiler来监控下调用的过程。可以从之前文章中的源码TestIds4项目中,实现持久化的存储,改造注入代码如下。

好了,现在可以配合网关来测试下客户端登录了,打开PostMan,启用本地的项目,然后访问之前配置的客户端授权地址,并开启SqlServer监控,查看运行代码。
访问能够得到我们预期的结果且查询全部是dapper写的Sql语句。且定期清理任务也启动成功,会根据配置的参数来执行清理过期授权信息。
四、使用Mysql存储并测试
这里Mysql重写就不一一列出来了,语句跟sqlserver几乎是完全一样,然后调用.UseMySql()即可完成mysql切换,我花了不到2分钟就完成了Mysql的所有语句和切换功能,是不是简单呢?接着测试Mysql应用,代码如下。


可以返回正确的结果数据,扩展Mysql实现已经完成,如果想用其他数据库实现,直接按照我写的方法扩展下即可。
五、总结及预告
本篇我介绍了如何使用Dapper来持久化Ids4信息,并介绍了实现过程,然后实现了SqlServer和Mysql两种方式,也介绍了使用过程中遇到的技术问题,其实在实现过程中我发现的一个缓存和如何让授权信息立即过期等问题,这块大家可以一起先思考下如何实现,后续文章中我会介绍具体的实现方式,然后把缓存迁移到Redis里。
下一篇开始就正式介绍Ids4的几种授权方式和具体的应用,以及如何在我们客户端进行集成,如果在学习过程中遇到不懂或未理解的问题,欢迎大家加入QQ群聊637326624与作者联系吧。
相关文章:
- AspNetCore中使用Ocelot之 IdentityServer4 
- Ocelot-基于.NET Core的开源网关实现 
- .NET Core微服务之基于Ocelot+IdentityServer实现统一验证与授权 
- Swagger如何访问Ocelot中带权限验证的API 
- Ocelot.JwtAuthorize:一个基于网关的Jwt验证包 
- .NET Core微服务之基于Ocelot实现API网关服务 
- .NET Core微服务之基于Ocelot实现API网关服务(续) 
- .NET微服务体系结构中为什么使用Ocelot实现API网关 
- Ocelot简易教程(一)之Ocelot是什么 
- Ocelot简易教程(二)之快速开始1 
- Ocelot简易教程(二)之快速开始2 
- Ocelot简易教程(三)之主要特性及路由详解 
- Ocelot简易教程(四)之请求聚合以及服务发现 
- Ocelot简易教程(五)之集成IdentityServer认证以及授权 
- Ocelot简易教程(六)之重写配置文件存储方式并优化响应数据 
- Ocelot简易教程(七)之配置文件数据库存储插件源码解析 
- ASP.NET Core中Ocelot的使用:API网关的应用 
- ASP.NET Core中Ocelot的使用:基于Spring Cloud Netflix Eureka的动态路由 
- ASP.NET Core中Ocelot的使用:基于服务发现的负载均衡 
- 【.NET Core项目实战-统一认证平台】第一章 功能及架构分析 
- 定制Ocelot来满足需求 
- 【.NET Core项目实战-统一认证平台】第三章 网关篇-数据库存储配置(1) 
- 【.NET Core项目实战-统一认证平台】第四章 网关篇-数据库存储配置(2) 
- 【.NET Core项目实战-统一认证平台】第五章 网关篇-自定义缓存Redis 
- 【.NET Core项目实战-统一认证平台】第六章 网关篇-自定义客户端授权 
- 【.NET Core项目实战-统一认证平台】第七章 网关篇-自定义客户端限流 
- 【.NET Core项目实战-统一认证平台】第八章 授权篇-IdentityServer4源码分析 
原文地址:https://www.cnblogs.com/jackcao/p/10058274.html
.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 
