JWT相信大家都有所了解,一种无状态的认证方式,因为JWT本身就能存储一些非敏感的身份信息,这种方式目前也被广泛使用,在陈某之前的Spring Cloud Gateway整合Spring Security OAuth2中使用的就是JWT。,但是JWT虽好,使用过程中还是要依赖缓存,比如退出登录,JWT唯一的失效途径就是等待过期时间失效,因此在退出登录时必须借助外力Redis才能达到效果。这个在之前的文章中也有介绍。,既然都要用Redis,为什么不采用Redis+Spring Security+OAuth2的认证方式呢?这种方式也是企业中经常采用的方案。,今天就介绍一下码猿慢病云管理系统中是如何将利用Redis和Spring Security 整合实现分布式统一认证登录的。,在学习这节内容之前先要了解Spring Security OAuth2 各种授权模式,在知识星球中《精尽Spring Cloud Alibaba》专栏有详细的介绍和案例代码演示,有需要的先去学习。,既然是直接使用Redis+Spring Security,身份信息肯定是存储在Redis中且token也不是JWT生成的令牌,如下图:,图片,可以看到令牌和刷新令牌以及身份信息都存储在Redis中。其中9d22b664-8540-48d1-98ed-4df1ce90b74f就是生成的令牌,无任何特殊含义,只是随机生成的UUID,相较于JWT短小了很多。,码猿慢病云管理系统中需要登录的客户端如下:,今天先来介绍前三种,后面的两种后文介绍。,登录页面如下:,web端登录,三个参数:,请求的报文如下:,因为是多租户的模式,所以在登录中做了医院的选择,这点也是对代码改造的一部分,下文介绍如何改造。,PDA是护士的手持设备,用于采集数据,因此也是需要认证才能上传、查看数据。,PDA端登录只需要护士输入如下两个参数:,为什么呢?不需要选择医院吗?,前面的文章中也有介绍过,PDA这种手持设备只有在平台上录入了才能使用,录入的地方:设备管理->设备列表->新增,图片,设备SN号是设备的唯一识别号,在设备取得注册证书后颁发的,所以可以作为唯一识别标志。,这里就是根据根据SN号去唯一关联这台设备,这也就是为什么PDA登录不用选择医院的原因。,PDA在发出登录请求时只需要携带这个SN号,请求报文如下:,平板一般是医生查房时作为移动端使用,住院医生每天都需要去病房查看病人病情,需要结合测量的数据才能了解患者的病情,因此PAD也是需要医生认证登录。,PAD端登录其实有两种方案:,码猿慢病云管理系统采用的第一种方案,需要选择医院,请求报文如下:,上面介绍的WEB端、PDA端、PAD端都是基于密码模式改造的,在介绍认证流程之前需要将登录接口给导入接口工具,这里使用的是Apifox,下载下方密码模式脚本,直接导入Apifox。,导入成功后,你将会得到一个接口,如下图:,图片,点击运行,发出请求登录,返回的信息如下图:,图片,上述返回信息几个比较重要的属性如下:,这个则是认证成功生成token,后续请求资源时只需要携带这个token则能通过认证,PS:这里的token似乎很短小,其实并不是JWT生成token,而是UUID。,这个是token过期后的刷新令牌,当token过期后则拿着这个refresh_token即可重新获取新的access_token,无需再次认证登录,这部分是当前用户登录成功后返回一些个人信息,比如权限、医院ID、所属的科室/病区ID等,详细信息如下图:,图片,对应的资源的权限,密码模式的登录有两个点比较重要,以WEB端登录报文为例:,从上面的报文可以看到有两处进行了加密,如下:,先上一张整体的流程图,如下:,图片,按照Apifox的密码模式登录接口发出登录请求后,将会按照上方的流程图逐一处理,流程解析如下:,网关的前置处理分为两个部分:,这两个功能都是使用过滤器处理的,在网关的配置文件中可以看到对认证中心codeape-auth配置了两个过滤器,如下:,图片,关于网关的过滤器不理解的请看知识星球中《精尽Spring Cloud Alibaba》专栏网关的部分。,在前面文章中介绍了码猿慢病云管理系统中是对WEB端、PDA端、PAD端将验证码关闭的,但是对于院外患者端,比如患者APP端还是需要验证码的。,验证码对应的代码在com.code.ape.codeape.gateway.filter.ValidateCodeGatewayFilter中,里面的逻辑在前文介绍过,这里就不再详细说了,有一行代码需要注意一下,代码如下:,为什么需要注意呢?,上文说过,客户端ID和客户端秘钥是放在Authorization中经过base64编码后发送给服务端,因此后端取client_id是不是也要经过解码,WebUtils.getClientId(request)这个方法就是对Authorization解码获取client_id,代码如下:,密码解密对应的过滤器:com.code.ape.codeape.gateway.filter.PasswordDecoderFilter,逻辑很简单:,代码很简单,注释很清楚,这里就不再详细贴出来了。,注意:客户端和服务端的加密因子需要保持一致才能正确加解密。,这个过滤器的作用是用于 OAuth2 的客户端身份验证,主要用于处理客户端使用客户端凭证(client credentials)访问受保护资源的情况。,整体的逻辑如下图:,这个很好理解,只有登录请求/oauth2/token才会校验客户端信息,其他的请求直接放行,这行代码是将请求头中客户端信息提取出来转换为Authentication客户端认证对象,这里用到了认证转换器AuthenticationConverter,在该过滤器构造时默认传入了四个,如下图:,this.authenticationConverter.convert(request)该方法调用的是DelegatingAuthenticationConverter#convert方法,内部是循环调用上述的四个才转换器,如下:,上述四个认证转换器比较重要的是其中两个:,1. ClientSecretBasicAuthenticationConverter,这个是处理将客户端信息存放在请求头中转换器,在内部对请求头中的客户端信息进行base64解码,具体的代码逻辑如下:,这个转换器正好是码猿慢病云管理系统中的请求方式相匹配,因此走的则是这个逻辑。,2. ClientSecretPostAuthenticationConverter,这个转换器是处理POST请求,且客户端信息通过Body传输的,里面逻辑也是非常简单,直接从请求参数中获取client_id和client_secret,具体的代码就不带大家看了,有兴趣可以看一下。,这里就是执行真正的校验逻辑了,内部调用的RegisteredClientRepository#findByClientId()方法校验。,对应的则是整体的流程图的第②部分,这里调用的则是自定义的CodeapeRemoteRegisteredClientRepository#findByClientId方法,内部逻辑非常简单:查询Redis缓存,存在缓存直接取,不存在则查数据库codeape/sys_oauth_client_details(通过feign接口远程调用服务查询)。,代码如下图:,这部分是客户端认证成功的处理逻辑,是将客户端认证的信息存放到SecurityContext上下文中,方便后面流程获取,代码OAuth2ClientAuthenticationFilter#onAuthenticationSuccess如下:,处理客户端认证失败的结果,这里最终执行的是自定义的失败处理器CodeapeAuthenticationFailureEventHandler#onAuthenticationFailure(),这个下文会介绍。,这个是客户端的持久层查询的类,在上文已经介绍过,OAuth2TokenEndpointFilter 这个过滤器的作用是用于处理 OAuth2 认证和授权请求的。它会拦截所有请求,并根据请求的 URI 判断是否是授权请求(/oauth2/token)。,如果是授权请求,则它会根据请求的参数构造一个 OAuth2AuthenticationToken 对象,并将其交给 AuthenticationManager 进行身份认证。如果认证成功,则根据请求中携带的授权类型(grant_type)决定使用哪个 OAuth2 授权提供者来生成授权令牌(access_token),并将生成的授权令牌返回给请求方。,如果认证失败,则返回相应的错误信息。该过滤器通常用于实现 OAuth2 认证和授权功能的后端服务。,这个过滤器才是真正处理登录请求逻辑,整体的逻辑如下:,这个在第4步中的第②个步骤,会根据请求中的参数和授权类型组装成对应的授权认证对象。它的几个重要的实现类如下:,先来看一下自定义的抽象类:OAuth2ResourceOwnerBaseAuthenticationConverter,三个抽象方法如下:,实现的convert()方法代码如下:,注释非常清晰了,这里不再详细解释了。,其中密码模式认证登录的实现类是:OAuth2ResourceOwnerPasswordAuthenticationConverter,里面的逻辑非常简单,这里不介绍了。,后续如有其他授权模式,直接继承OAuth2ResourceOwnerBaseAuthenticationToken扩展,AuthenticationProvider是Spring Security提供的一种机制,用于接收和验证用户名和密码等认证信息,并返回一个已认证的Authentication对象。其作用是封装了整个认证过程,包括认证用户的来源、密码的加密和解密、对用户账户状态的判断等。,AuthenticationProvider在第4步中的第③步中被调用,用于认证;码猿慢病云管理系统中自定义了三个实现类,如下:,1)OAuth2ResourceOwnerBaseAuthenticationProvider,抽象类,封装了具体的执行逻辑,有三个抽象方法供子类实现,如下:,具体的执行逻辑都在OAuth2ResourceOwnerBaseAuthenticationProvider#authenticate()方法中,关键逻辑如下:,代码①:构建认证登录对象,提供了一个buildToken抽象方法交由子类实现,剩余代码下文介绍,2)OAuth2ResourceOwnerPasswordAuthenticationProvider,密码模式的AuthenticationProvider,继承抽象类OAuth2ResourceOwnerBaseAuthenticationProvider实现三个抽象方法,逻辑很简单。,3)OAuth2ResourceOwnerSmsAuthenticationProvider,短信验证码登录模式的AuthenticationProvider,继承抽象类OAuth2ResourceOwnerBaseAuthenticationProvider实现三个抽象方法。,从DaoAuthenticationProvider这里就进入真正的认证逻辑了,从名字就可以看出涉及到数据库的操作了。内部的逻辑很简单,就是通过UserDetailService调用查询用户信息封装成UserDetails,在第7步中的第②步骤中则会进入:,码猿慢病云管理系统中自定义了一个CodeapeDaoAuthenticationProvider,执行的逻辑将会在这个类中,先看下其中重载的两个重要的方法:,retrieveUser这个方法逻辑很简单,则是调用UserDetailService查询用户信息,逻辑如下:,图片,代码①,从Request中获取相关参数:,代码②,从IOC容器中获取UserDetailSevice,码猿慢病云管理系统中目前实现类有三个:,代码③,调用UserDetailService中的loadUserByUsernameAndOther方法获取UserDetails,这个方法核心逻辑则是校验密码,码猿慢病云管理系统中的密码校验是通过PasswordEncoder加密。,图片,核心逻辑在:AbstractUserDetailsAuthenticationProvider.DefaultPreAuthenticationChecks#check方法中,代码如下:,图片,在第8步中说到查询用户信息是通过UserDetailService查询,码猿慢病云管理系统中目前内置三个实现类:,这里都是通过feign调用解耦,当然你也可以在auth模块嵌入数据库,从数据库查询,这里调用的方法是loadUserByUsernameAndOther,比如CodeapeUserDetailsServiceImpl实现如下:,图片,最终的组装UserDetails通过getUserDetails方法,如下:,图片,需要注意的是:码猿慢病云管理系统中的用户信息是封装在CodeapeUser中,方便后续扩展,其中的属性如下:,图片,可以看到这里和登录返回的信息中user_info是对应的:,图片,在第7步中的第③步中生成access_token,自定义的实现类为:CustomeOAuth2AccessTokenGenerator,图片,在第7步中的第⑤步骤中执行了令牌的持久化,Spring Security 默认支持两种持久化方式:,码猿慢病云管理系统中扩展了Redis中持久化,自定义的实现类:CodeapeRedisOAuth2AuthorizationService,图片,持久化成功后将会在Redis中看到对应的信息:,图片,在第4步中的第④步骤中认证成功,则调用AuthenticationSuccessHandler 处理登录成功的逻辑,将认证信息输出返回给客户端。,码猿慢病云管理系统中自定义类:CodeapeAuthenticationSuccessEventHandler,图片,本节内容详细介绍了码猿慢病云管理系统中完整的认证登录生成token的流程,相信你对整体的流程有了清晰的了解。
文章版权声明
1 原创文章作者:cmcc,如若转载,请注明出处: https://www.52hwl.com/28875.html
2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈
3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)
4 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别