需求:将项目从springSecurity验证登录改为统一认证sso登录,将原数据库中用户账号、密码、邮箱信息迁移至统一认证端数据中,保留原客户端项目的使用SpringSecurity进行权限角色管理部分
最终选择spring boot +oauth2 ,用到 @EnableOAuth2Sso注解实现单点登录,主要参考:
Spring Boot+OAuth2,一个注解搞定单点登录! - 江南一点雨 (javaboy.org)
本文记录踩坑与学习与实战记录(未更完)
目录
Spring Security基于oauth2的sso单点登录(最后使用的方式)
一.基础知识学习
1.1 cas和sso(了解):
【单点登录】什么是 SSO 与 CAS?_happydecai的博客-CSDN博客_cas和sso
sso是一种框架,cas是实现sso的一种方法,当然,还有其他的方法,例如cookie
1.1.1 cas
从结构上看,CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。下图是 CAS 最
链接:单点登录之CAS原理和实现_金玉良缘-CSDN博客_cas单点登录实现原理
1.1.2 cas和oauth2 的区别
CAS的单点登录和oauth2的最大区别 - 剑握在手 - 博客园
1.1.3. 通过cas实现单点登录
Spring Security 集成CAS实现单点登录 - 阿狸哥哥 - 博客园
1.2 Spring Security
security 有认证和授权两个功能 以session作为交互
1.2.1 身份认证流程解析
最简单易懂的Spring Security 身份认证流程讲解 - 曾俊杰的专栏 - 博客园 (cnblogs.com)
1.2.2 自定义用户密码验证
关于密码验证源码解读写于0706 · 语雀 (yuque.com)
重写密码验证filter:
SpringSecurity的自定义用户密码验证 - 洋洋哥 - 博客园 (cnblogs.com)
1.2.3 Sprint Security 用户权限管理
1. 在config配置文件中配置:分为hasAuthority(String)、hasRole(String)、hasIpAddress(String)
(2条消息) Spring Security--角色权限判断_我和井盖都笑了博客-CSDN博客_springsecurity 判断权限
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**").hasAnyRole("ROLE_USER", "ROLE_ADMIN")
.antMatchers("/admin/**").hasRole("ROLE_ADMIN")
// 如果发来的请求是指定的 IP 就允许访问
// 可以通过 request.getRemoteAddr()获取 ip 地址。
.antMatchers("/api/**").hasIpAddress("localhost")
.antMatchers("/api/**").hasAuthority("admin")
.and().logout().deleteCookies("JSESSIONID", oauthCookieName).invalidateHttpSession(true)
// 这样保证在客户端logout的时候就在服务端logout
.logoutSuccessUrl("http://{server.ip}/logout")
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
// 保证只有单方登录,同时需要在auth端也配置这条,客户端/logout了同时就会在统一认证端也执行logout
http.sessionManagement().maximumSessions(1).expiredUrl("/logout");
}
2. 使用注解@PreAuthorize 进行管理权限
@PreAuthorize 注解,顾名思义是进入方法前的权限验证,@PreAuthorize 声明这个方法所需要的权限表达式,例如:@PreAuthorize("hasAuthority('sys:dept:delete')"),
@PreAuthorize 权限控制的原理 - 简书 (jianshu.com)
3. 自定义注解进行权限管理
(2条消息) Java自定义注解实现权限管理_小识的博客-CSDN博客_注解实现权限管理
1.2.4 做到一个用户只能登录一次
1. 最大同时登录为1,且配置session过期重定位地址,直接将原来登录处踢出
当spring security检查到session过期后,若未做任何配置,spring security会返回一个用户不友好的页面,因此我们通常需要设置一个地址,当spring security检查到session过期后,将请求重定位到我们的地址上,设置代码如下所示:
http
.sessionManagement().maximumSessions(1).expiredUrl("/logout");
参考链接:
spring scurity session管理 - SegmentFault 思否
2. 当再次登录时阻止其认证而不是强制踢出上一次登录:
当一个用户已经认证过了,在另外一个地方重新进行登录认证,spring security可以阻止其再次登录认证,从而保持原来的会话可用性;具体的代码设置如下所示
http.sessionManager().maximumSession(1).maxSessionsPreventsLogin(true);
参考链接:
spring security 关于 http.sessionManagement().maximumSessions(1);的探究 - 岑惜 - 博客园 (cnblogs.com)
1.2.5 Cookie、Session、Token
1. 三者的关系
springbsecurity 登录token验证过滤器_彻底理解 Cookie、Session、Token_weixin_39693662的博客-CSDN博客
2. springsecurity session详解:
参考:
Spring Security 控制Session详解 - 简书 (jianshu.com)
3. springSecurity 修改session中的信息
遇到场景 : 前端通过session获取当前用户信息,当前用户信息在前端页面发生了改变时(比如用户update了自己的email属性);可能数据库里面已经update了,而程序没有重启或者用户没有重新登陆,则session中的值是不会发生改变的,即验证的用户信息也是不变的,前端显示也并不会更新
SpringSecurity-日常踩坑,修改session中的用户信息。 - EalenXie - 博客园 (cnblogs.com)
4. 根据session获取用户名
SpringSecurity-日常踩坑,修改session中的用户信息。 - EalenXie - 博客园 (cnblogs.com)
1.3 Spring Security基于oauth2的sso单点登录(最后使用的方式)
1. oauth2 主要目的是为了第三方登录(例如微信授权), 提供以token作为访问权限
参考:Spring Security基于Oauth2的SSO单点登录怎样做? - 程序员大本营
2. 当客户端用security时:(2条消息) 基于Spring Security + OAuth2 的SSO单点登录(客户端)_Janche的博客-CSDN博客_oauth2 客户端登录
3. @EnableOAuth2Sso注解实现单点登录(在客户端使用,客户端用的是security验证登录)
(最终参考的方案)
Spring Boot+OAuth2,一个注解搞定单点登录! - 江南一点雨 (javaboy.org)
auth端连接数据库验证用户账号和密码需要配置datasource config需要配置
客户端有单独的权限管理,在security中配置,详见"Sprint Security 用户权限管理"
4. 注册
spring-security-oauth2(二十二) 重构注册逻辑_codeing-tiger-CSDN博客_oauth2 注册
1.4 开源框架XXL-SSO
实现时遇到的问题:
做了很多尝试把xxl-sso框架和springSecurity框架集成,但客户端无法获取用户信息,无法实现原因:统一验证那边验证登录成功了,两边的session统一,但是客户端项目的security验证没有通过,而我们需要它的username password拦截器验证通过,才能获得我们所需要的principal
二. 实战:
参考项目地址:
https://github.com/lenve/oauth2-samples
clone项目后分别打开oauth2-sso/auth-server(认证端)、oauth2-sso/client1(客户端1)、oauth2-sso/client2(客户端2),开启后可以实现统一认证登录
接下来进行一些拓展:
2.1 客户端登录成功后跳转index页面
传送门:
SpringBoot 登陆后跳转到index页面_aqing617的博客-CSDN博客
2.2 客户端登出
客户端的登出添加配置
http
.logout()
// .logoutUrl("/logout")
// .deleteCookies("s1","JSESSIONID")
// 在登出后,是否要清空当前session
// .invalidateHttpSession(true)
// 服务端登出
.logoutSuccessUrl("http://localhost:1111/logout");
认证端添加的配置:
http
.logout();
2.3 一个用户只允许登录一次
需求:每个用户在浏览器a登录后,在浏览器b再次登录,此时要求浏览器a 该用户被踢出
在认证端和客户端都添加配置
http
.sessionManagement().maximumSessions(1).expiredUrl("/logout");
2.4 认证端连接数据库验证用户信息
原项目中,用户信息是存在与程序内存中的,现添加配置,使得用户信息存储于数据库中
1. securityConfig中替换
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(userAuthenticationProvider).userDetailsService(userService).passwordEncoder(passwordEncoder);
}
2. 添加datasourceConfig,连接数据库
通过添加import com.mysql.jdbc.Driver;自动在pom文件中添加依赖
搭建单点登录服务器,新建数据库用户表用于用户验证
3. 注入bean
4. 定义user类,实现UserDetails接口
5.定义UseDAO
6. 定义UserService实现UserDetailService接口
7.添加认证处理类,即1.中所用的
8. application.properties添加配置,连接数据库
2.5 新增user-center客户端,用于展示引导链接到各个客户端
首先在认证端新增接口,登录成功后跳转用户中心客户端
@GetMapping("/")
public void redirect2UserCenter(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.sendRedirect("http://localhost:1112");
}
(未完待续)
2.6 添加统一认证端的注册逻辑
在认证端新增注册接口,调用后转发调用客户端接口,在认证端数据库和客户端数据库都添加用户信息
(未完待续)
2.7 客户端权限管理
(未完待续)
遇到的问题:
(未完待续)
用户权限管理时
尝试了多种方法解决用户权限管理,用security自己的配置(获取不到aizoo数据库中的权限信息,只能获取统一身份认证的),@PreAuthorize(同样的问题),自己写了拦截器和自定义注解拦截无果(拦截顺序的问题,无法跳转到统一身份认证)
auth端无法跳转index,无法直接访问任何接口
试图解决统一认证服务器登录之后无法跳转index的bug,尝试了后台控制跳转,报401错误(没有权限