上一篇我们已经搭建了一个简单的前后端不分离的认证框架
但是在集成过程中,出现了一些问题
1.跨域Cookie
2.重定向页面无法定位到网关
3.想要进行一些后置加工处理操作
4.不想要每次验证都需要请求远端身份提供商
常见的解决方案是自定义一个资源服务器,然后让后端请求这个自定义的资源服务器
或者是修改Spring Security框架,增加后置流程,
上述两个解决方案都并不简单,但是迫于一些时间压力,在我尝试集成OIDC的时候,我选择了第二种解决方案
即修改Spring Security框架的流程,将相关认证化为自己的流程框架
首先我们明确了Spring Security的书写流程
首先在Spring Security框架中
提供了不同的EndPoint供我们自己去自定义一些实现
比如说,我在内网进行集成SSO,访问所有的接口都需要proxy
那么我们就可以
.tokenEndpoint()
.accessTokenResponseClient(responseClient) |
自定义一个responseClient
传入一个RestTemplate
方便自定义网络交互
那么我们自定义的第一步,就是先书写一个存放Token的地方,方便存入Token
由于OIDC 的 OAuth2AccessToken 和 Spring Security传统的 OAuth2AccessToken 数据类型不一致,故考虑自定义实现一个TokenStore
由于用户权限较多,故考虑使用Redis,实现自定义的TokenStore
那么这一步,具体代码由于不能脱敏,故不贴上,但是还是围绕原本的RedisTokenStore进行书写
实现对应的从Token -> ReFresh_Token
Token -> Auth
ReFresh -> Token 等互转及存储接口即可
实现完成之后,我们在Spring Security框架中暴露的authizedClientRepository注入自定义的clientRepository
clientRepository 包含了实现的mySelfTokenStore
然后在clientRepository中实现了saveAuthorizedClient
将传入的Authtication 自定义加工一下,带着对应的token,存入tokenStore
这样,就存储完成了Token到Redis中
之后就可以返回给页面了
由于默认返回,是直接返回当前服务约定的一个uri
也就是说,我的服务在8081端口上,我约定返回/token,那么其返回的就是
localhost:8081/token
而我的gateway部署在88端口上,这样直接交给框架是不现实的
故考虑利用login成功后,框架提供的successHandler()来进行处理
其中我们可以从ThreadLocal中取出Token
从request中获取x-forwarded-host这个header
利用respon的sendRedirect来重定向到localhost:88/token?token=xxxxxx
方便前端获取到token并存储
接下来我们就需要考虑用户使用过程中的整体流程
首先是一个Filter,用于校验用户是否登录,并将用户的相关信息,存入SecurityContextHolder
之后在接口上利用@PreAuthorize进行权限校验,对于如何实现@PreAuthorize中的权限校验,可以参考如下的文章
https://blog.csdn.net/weixin_47345400/article/details/108666451
之后别忘了在SpringSecurityConfig中声明全部接口的permit()
完成这个操作之后,就已经完成了用户使用过程中的token交互
之后就是Token自身的声明周期
涉及的接口有checkToken / freshToken / logout
1.checkToken相对简单
只需要根据token是否存在,返回boolean信息
2.logout
则是分别删除accessToken / authentication / refreshToken信息
3.freshToken则需要网络交互
根据传入的token,利用上一章说的access_token接口,尝试获取新的接口
然后再一次请求user_info,获取到用户信息
并删除redis相关信息
再次存入,返回前端新的token
这样就基本完成这一次的书写
整体流程总结如下图