源码地址 | 12级程序猿-新年正当红/springboot3.0+spring security6+oauth2+vue3整合单点登陆(sso) |
项目介绍
- springboot3.0使用jdk17
- redis提前安装好
hosts配置
在C:\Windows\System32\drivers\etc\hosts
127.0.0.1 auth-server
127.0.0.1 res-server
127.0.0.1 dianshang
127.0.0.1 kucun
后端介绍
- auth-server是认证授权服务(登录授于权限)
- res-server 是资源服务(共享给第三方客户端的内容)
- dianshang (电商项目,客户端)
- kucun (库存项目,客户端)
- 电商和库存项目代码都一样,就是为了演示多个客户端去认证(登陆)
- 先启动auth-server,在启动其他项目
sql脚本在sql目录下
vue项目安装
npm install
vue项目启动
npm run dev
vue项目介绍
- renzheng-vue 是统一认证平台,所有的客户端都会跳转到这里登陆,登陆成功后,在重定向到自己的界面
- dianshang-vue 是电商项目客户端,和库存代码差不多,唯一的区别就是配置参数和接口不一样
- kucun-vue 是库存项目客户端,和电商代码差不多,唯一的区别就是配置参数和接口不一样
登陆流程
1.组装授权码url,进行登陆
2.在统一认证中心输入账号密码,点击登陆会返回认证id,把认证id放入cookie
3.拿着认证id拼接跳转地址,进入授权码回调界面
4.拿着授权码获取token,把token放入cookie
5.拿着token放入请求头中获取资源服务数据
6.拿着token放入请求头中获取客户端数据
7.退出登陆后,清空cookie,并跳转到登陆界面
vue项目启动访问浏览器
访问电商登陆界面,选择单点登陆
跳转到了统一认证中心进行登陆,输入账号:zhangsan,密码:123456
登陆成功后,获取目标地址,跳转授权码接口,进入回调界面,获取token,并跳转到首页
访问库存登陆界面
选择单点登陆
这次就不需要再进入统一认证中心了,直接获取授权码,进入回调界面,获取token,并跳转到首页
退出登陆
电商系统选择退出登陆,跳转到登陆界面
库存系统刷新界面,也跳转了登陆界面
代码分析
授权获取token分析
在dianshang-vue的项目中 登陆方法会拿着拼接好的获取授权码地址,跳转到统一认证中心
去登录,如果有认证id,那么带着认证id,去后台就会从缓存中获取上下文,如果上下文存在
就不需要再次登陆,直接进入回调界面,如果认证id不存在,那么就需要登陆
http://auth-server:8084/oauth2/authorize?response_type=code&client_id=dianshang&scope=openid&redirect_uri=http://localhost:3001/callback
和kuucn-vue不同的就是参数,client_id改成库存的客户端id,
redirect_uri改成库存的回调地址
当跳到回调界面的时候,会从浏览器拿到授权码也就是code参数,请求后端获取token
后端会返回token,然后吧token放入cookie中,访问其他接口的时候,放入请求头中
在auth-serverx项目中,获取oauth2提供的获取token接口
com.dmg.authserver.controller.AuthController#getToken
在http请求的时候 会把Basic放入header头中
登陆分析
在auth-server项目的登陆方法中,会把认证的信息放入上下文中,并生成认证id,把上下文放入缓存中,并吧id 返回给前端
com.dmg.authserver.service.impl.LoginServiceImpl#login
在renzheng-vue的项目中App.vue的登陆方法中,会从后台拿到一个认证id,然后吧认证id 放入cookie中,在退出登陆的时候,使用这个认证id 进行退出 并吧缓存中的数据删除
后端auth-server要放行登陆和获取token的接口,要不然vue访问不了
认证过滤器分析
在auth-server的项目中,只要有认证id 存在,就去缓存中获取上下文,
如果上下文存在,那么放入持有人手中,必须放,否则上下文就是空的,那么说明 不需要登陆了,如果不存在,就需要去下一个过滤器链
com.dmg.authserver.filter.MyAuthenticationFilter#doFilterInternal
缓存上下文仓库分析
com.dmg.authserver.repository.RedisSecurityContextRepository#loadDeferredContext
当底层源码读取上下文的时候,会从缓存中获取是否存在,认证id会在浏览器的参数或者Header中,如果存在,就不需要登陆了,如果不存在,那么就需要登陆
在授权服务安全过滤器链需要先配置上下文
源码分析
org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter#doFilterInternal
这个方法中只要authorizationRequest是null 就是已经认证授权过的了,如果有值,那么说明没有认证授权, 那么就会一直重定向到登陆界面
org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter#sendAuthorizationResponse
在下面的方法中,就是登陆成功后,获取授权码的地方,authorizationCodeRequestAuthentication.getAuthorizationCode().getTokenValue()
拼接url参数,已经回调地址,然后重定向到客户端对应的界面,并显示?code=xxx
自定义登陆跳转端点
com.dmg.authserver.point.MyLoginUrlAuthenticationEntryPoint#commence
原生的跳转是不支持前后分离的,所以需要继承LoginUrlAuthenticationEntryPoint
重写commence方法
获取当前浏览器的请求路径和参数,给他拼接一个target,这个target在前端会截取,并跳转到授权码界面,要不然前端无法跳转
在安全配置过滤器链中设置自定义的跳转登陆端点,跳转路径为前端的统一认证中心地址
com.dmg.authserver.config.SecurityConfig#authFilterChain
资源服务分析
在安全配置这里,会拿着jwt令牌进行解析授权端点(issuer-uri)的内容
客户端分析
com.dmg.dianshang.filter.MyAuthenticationFilter#doFilterInternal
在客户端的认证过滤器中会拿着 token,去资源服务器获取权限,然后放入认证信息中
并把认证信息放入上下文持有人手中,这样在访问客户端的其他接口,就不会出现401和403的错误了
Cookie
因为是多个系统只要1个登陆,其他就不需要登陆,那么令牌和认证id,都放在了cookie中
当退出登陆的时候,也要把cookie清除掉
客户端注册
com.dmg.authserver.controller.TestController#registerClientDianShang
输入对应的客户端id(唯一),客户端密码,客户端名称,和回调地址(前端获取授权码的地址)
最后会添加到oauth2_registered_client表中
缓存中的数据
rzId:为前缀,后面是uuid
内容就是安全上下文