spring boot:spring security+oauth2+sso+jwt实现单点登录(spring boot 2.3.3)
一,sso的用途 ?
1,如果有多个应用系统,用户只需要登录一次就可以访问所有相互信任的应用系统。
不需要每次输入用户名称和用户密码,
也不需要创建并记忆多套用户名称和用户密码。
2,系统管理员只需维护一套统一的用户账号,方便、简单。
而不必管理很多套的用户账号。
3, 如果需要开发新的应用系统,可以直接使用单点登录平台的用户认证服务,简化开发流程。
4,oauth和sso的区别:
oauth2解决的是服务提供方(微信等)给第三方应用授权的问题,
sso解决的是大型系统中各个子系统如何共享登陆状态的问题
说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest
对应的源码可以访问这里获取: https://github.com/liuhongdi/
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,演示项目的相关信息
1,项目地址:
https://github.com/liuhongdi/securityssojwt
2,功能说明:
演示了基于oauth2实现sso
3,项目结构:如图:



三,配置文件说明
1,ssoserver的 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--oauth2-->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.0.RELEASE</version>
</dependency>
<!--jwt-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency> <!--jaxb-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
2,ssoclient1的 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--oauth2-->
<dependency><groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.0.RELEASE</version>
</dependency>
<!--jwt-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
<!--oauth2 autoconfigure-->
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
3,ssoclient2的 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--oauth2-->
<dependency><groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.0.RELEASE</version>
</dependency>
<!--jwt-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
<!--oauth2 autoconfigure-->
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
4,ssoserver的application.properties
server.port = 8080
server.servlet.context-path = /server
spring.security.user.password=123456 #error
server.error.include-stacktrace=always
#log
logging.level.org.springframework.web=trace
logging.level.org.springframework.security=debug
5,ssoclient1的application.properties
security.oauth2.client.client-id=client1
security.oauth2.client.client-secret=client1secrect
#需要认证时候跳转的地址
security.oauth2.client.user-authorization-uri=http://127.0.0.1:8080/server/oauth/authorize
#请求令牌地址
security.oauth2.client.access-token-uri=http://127.0.0.1:8080/server/oauth/token
#解析
security.oauth2.resource.jwt.key-uri=http://127.0.0.1:8080/server/oauth/token_key
#security.oauth2.resource.jwt.key-value=imooc
#sso
server.port=8081
server.servlet.context-path=/client1
6,ssoclient2的application.properties
security.oauth2.client.client-id=client2
security.oauth2.client.client-secret=client2secrect
#需要认证时候跳转的地址
security.oauth2.client.user-authorization-uri=http://127.0.0.1:8080/server/oauth/authorize
#请求令牌地址
security.oauth2.client.access-token-uri=http://127.0.0.1:8080/server/oauth/token
#解析
security.oauth2.resource.jwt.key-uri=http://127.0.0.1:8080/server/oauth/token_key
#sso
server.port=8082
server.servlet.context-path=/client2
四,java代码说明:
1,ssoserver的WebSecurityConfig.java
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Resource
private SsoUserDetailsService ssoUserDetailsService; @Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
} @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(ssoUserDetailsService).passwordEncoder(passwordEncoder());
} @Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().and().authorizeRequests().anyRequest().authenticated();
}
}
2,ssoserver的SsoUserDetailsService.java:
@Component
public class SsoUserDetailsService implements UserDetailsService { @Autowired
private PasswordEncoder passwordEncoder; //本来应该从数据库加载数据,此处供仅演示
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("----------------------loadUserByUsername");
if (username.equals("laoliu") == false) {
throw new UsernameNotFoundException("用户名不存在");
}
return new User(username, passwordEncoder.encode("123456"),
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
}
}
3,ssoserver的SsoAuthorizationServerConfig.java:
@Configuration
@EnableAuthorizationServer
public class SsoAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { //配置供访问的客户端的账户
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
// 注册一个客户端,设置名称
.withClient("client1")
// 设置客户端阴匙
.secret(new BCryptPasswordEncoder().encode("client1secrect"))
// 对应客户端登录请求URI
.redirectUris("http://127.0.0.1:8081/client1/login")
// 授权方式
.authorizedGrantTypes("authorization_code", "password", "refresh_token")
// 授权范围
.scopes("all")
// 是否自动同意,如果采用非自动同意,则需要用户手动授权
.autoApprove(true)
.and().
withClient("client2")
.redirectUris("http://127.0.0.1:8082/client2/login")
.secret(new BCryptPasswordEncoder().encode("client2secrect"))
.authorizedGrantTypes("authorization_code", "password", "refresh_token")
.scopes("all")
.autoApprove(true);
} @Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConverter());
} @Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("isAuthenticated()");
} @Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
} @Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(){
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
//指定signkey
converter.setSigningKey("liuhongdi");
return converter;
}
}
4,ssoclient1的HomeController.java
@Controller
@RequestMapping("/home")
public class HomeController {
//查看登录后的用户信息
@RequestMapping("/session")
@ResponseBody
public String getsession(){
//session
String userone = SessionUtil.getCurrentUserName();
System.out.println("user:"+userone);
if (userone == null) {
return "not login";
} else {
return userone;
}
}
}
5,ssoclient1的SessionUtil.java
public class SessionUtil {
//得到security所保存的用户
public static String getCurrentUserName(){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication.isAuthenticated() && !(authentication instanceof AnonymousAuthenticationToken)) {
Object principal = authentication.getPrincipal();
//System.out.println(principal);
if (principal instanceof String) {
return (String)principal;
} else if (principal instanceof UserDetails) {
String currentuser = ((UserDetails) principal).getUsername();
return currentuser;
} else {
//System.out.println("not instanceof UserDetails");
}
return null;
}
return null;
}
}
6,其他非关键代码可访问github查看
五,测试效果
1,按以下顺序启动三个模块:
ssoserver
ssoclient1
ssoclient2
2,先访问client1,
http://127.0.0.1:8081/client1/home/session
会跳转到:
http://127.0.0.1:8080/server/login
如图:

我们输入用户名 laoliu,密码 123456
这个是写死在代码中的演示账号
登录后会跳转到:

这个url会打印当前登录用户的用户名
我们新打开一个标签页:
http://127.0.0.1:8082/client2/home/session
我们之前并未从client2登录,查看效果:

可以看到也已经登录
3,通过html页面跳转访问:
http://127.0.0.1:8081/client1/index.html
返回:

点击 访问client2 的链接

可正常访问
六,查看spring boot版本
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.3.RELEASE)
spring boot:spring security+oauth2+sso+jwt实现单点登录(spring boot 2.3.3)的更多相关文章
- 使用Spring Security OAuth2进行简单的单点登录
1.概述 在本教程中,我们将讨论如何使用Spring Security OAuth和Spring Boot实现SSO - 单点登录. 我们将使用三个单独的应用程序: 授权服务器 - 这是中央身份验证机 ...
- Spring Security OAuth2 SSO
通常公司肯定不止一个系统,每个系统都需要进行认证和权限控制,不可能每个每个系统都自己去写,这个时候需要把登录单独提出来 登录和授权是统一的 业务系统该怎么写还怎么写 最近学习了一下Spring Sec ...
- Spring Security OAuth2 SSO 单点登录
基于 Spring Security OAuth2 SSO 单点登录系统 SSO简介 单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自 ...
- 基于spring boot2.0+spring security +oauth2.0+ jwt微服务架构
github地址:https://github.com/hankuikuide/microservice-spring-security-oauth2 项目介绍 该项目是一个演示项目,主要演示了,基于 ...
- 【SpringSecurityOAuth2】源码分析@EnableOAuth2Sso在Spring Security OAuth2 SSO单点登录场景下的作用
目录 一.从Spring Security OAuth2官方文档了解@EnableOAuth2Sso作用 二.源码分析@EnableOAuth2Sso作用 @EnableOAuth2Client OA ...
- Spring Security构建Rest服务-1300-Spring Security OAuth开发APP认证框架之JWT实现单点登录
基于JWT实现SSO 在淘宝( https://www.taobao.com )上点击登录,已经跳到了 https://login.taobao.com,这是又一个服务器.只要在淘宝登录了,就能直接访 ...
- springBoot整合spring security+JWT实现单点登录与权限管理--筑基中期
写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...
- SSO之CAS单点登录详细搭建教程
本教程是我个人编写,花费几个小时的时间,给需要学习的人员学习使用,希望能帮助到你们. [环境说明]:本文演示过程在同一个机器上的(也可以在三台实体机器或者三个的虚拟机上),环境如下: windows7 ...
- Spring Cloud:Security OAuth2 自定义异常响应
对于客户端开发或者网站开发而言,调用接口返回有统一的响应体,可以针对性的设计界面,代码结构更加清晰,层次也更加分明. 默认异常响应 在使用 Spring Security Oauth2 登录和鉴权失败 ...
随机推荐
- 微信小程序常用样式
1.设置全局字体样式app.wxss: text{ font-family:MicroSoft yahei; } 2.设置弹性盒子模型: .container{ /*弹性模型*/ display:fl ...
- python之ddt模块使用
一.DDT(数据驱动)简介 Data-Driven Tests(DDT)即数据驱动测试,可以实现不同数据运行同一个测试用例(通过数据的不同来驱动测试结果的不同). ddt本质其实就是装饰器,一组数据一 ...
- python中使用token模拟登录
背景:在接口测试中我们经常是需要一个登陆token,或者获取其他用到的参数来关联下一个接口用到的参数. Token的意义及用法 一.Token的来源: 当客户端多次向服务端请求数据时,服务端就需要多次 ...
- pytest(3):pytest运行参数介绍
前言 pytest 带有很多参数,可以使用 pytest --help 来查看帮助文档,下面介绍几种常用的参数: 无参数 读取路径下所有符合规则的文件,类,方法,函数全部执行.使用方法如下: py ...
- vsCode 设置vue文件标签内的style智能提示
VS Code 文件->首选项->设置 搜索:files.associations 点击在setting.json中编辑 最后一行添加配置: "files.association ...
- JVM强引用、软引用、弱引用、虚引用、终结器引用垃圾回收行为总结
JVM引用 我们希望能描述这样一类对象: 当内存空间还足够时,则能保留在内存中:如果内存空间在进行垃圾收集后还是很紧张,则可以抛弃这些对象. -[既偏门又非常高频的面试题]强引用.软引用.弱引用.虚引 ...
- Node.js 从零开发 web server博客项目[日志]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- php处理的图片无法进CDN缓存
今天发现线上有个问题,线上一个图片域名,在前端已经加了CDN缓存,不落缓存,则用PHP动态实现图片缩放,但经PHP处理过的图片输出后,每次都要从后端读取,后端服务器压力瞬间增加,经分析,PHP中没有作 ...
- 现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?
Thread t1 = new Thread(new T1()); Thread t2 = new Thread(new T2()); Thread t3 = new Thread(new T3()) ...
- 1.5Hadoop的启动