【实测封神】Smart-SSO:5分钟搭建企业级单点登录系统,彻底终结多系统账号混乱难题
你是否还在为企业内部10+系统重复登录而抓狂?用户抱怨密码记不住,IT部门疲于账号管理,安全审计更是一团乱麻?今天给大家带来的Smart-SSO开源项目,基于SpringBoot+OAuth2打造,开箱即用的轻量级单点登录解决方案,完美解决跨系统认证难题。读完本文你将掌握:
- 3分钟完成SSO服务端部署的实操步骤
- 5行代码实现应用系统接入单点登录
- 分布式环境下的Token共享方案设计
- 前后端分离架构的权限控制最佳实践
- 从0到1搭建企业级认证中心的完整指南
一、为什么选择Smart-SSO?市面方案深度横评
企业级单点登录(Single Sign-On,SSO)方案选型一直是架构师的头疼事。我们对当前主流实现方案进行了全方位对比:
| 特性 | 传统Session共享 | JWT令牌 | OAuth2.0标准 | Smart-SSO(OAuth2增强版) |
|---|---|---|---|---|
| 单点登录 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
| 单点退出 | ✅ 需额外开发 | ❌ 难以实现 | ✅ 原生支持 | ✅ 一键退出所有系统 |
| 踢人下线 | ✅ 需额外开发 | ❌ 无法实时失效 | ✅ 需扩展实现 | ✅ 管理员实时管控 |
| 过期自动续签 | ❌ 依赖Cookie | ❌ 需双Token改造 | ✅ 原生支持 | ✅ 无感自动续签 |
| 跨域支持 | ❌ 受浏览器限制 | ✅ 支持 | ✅ 支持 | ✅ 全场景跨域解决方案 |
| 前后端分离 | ❌ 不适用 | ✅ 支持 | ✅ 支持 | ✅ 无Cookie模式优化 |
| 按钮级权限 | ✅ 需定制开发 | ❌ 难以实现 | ❌ 需扩展实现 | ✅ 原生支持API级控制 |
| 分布式部署 | ❌ 集群依赖 | ✅ 支持 | ✅ 需共享存储 | ✅ Redis无缝集群 |
| 性能损耗 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ 本地缓存优化 |
| 接入复杂度 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐ | ⭐⭐ 5行代码快速接入 |
Smart-SSO核心优势在于:基于OAuth2.0标准协议,却优化了其在企业内部系统的使用痛点。通过客户端本地Token缓存减少80%的服务端请求,独创的"双Token+Redis存根"机制,既保留了JWT的无状态优势,又实现了类似Session的实时管控能力。
二、架构解析:Smart-SSO的底层实现原理
2.1 核心组件架构
Smart-SSO采用微服务架构设计,主要包含四大模块:
classDiagram
class 服务端模块 {
+认证授权中心
+用户权限管理
+Token生命周期管理
+客户端应用管理
}
class 客户端模块 {
+登录过滤器
+权限过滤器
+Token本地缓存
+自动续签组件
}
class 存储模块 {
+Redis分布式存储
+本地内存缓存
+数据库持久化
}
class 扩展模块 {
+前后端分离支持
+跨域解决方案
+按钮级权限控制
}
服务端模块 <--> 客户端模块 : OAuth2.0协议通信
服务端模块 <--> 存储模块 : Token/权限数据
客户端模块 <--> 存储模块 : 本地缓存
服务端模块 <--> 扩展模块 : 功能扩展点
2.2 单点登录流程(OAuth2.0授权码模式增强版)
sequenceDiagram
participant 用户
participant 客户端应用
participant SSO服务端
participant Redis存储
用户->>客户端应用: 访问受保护资源
客户端应用->>用户: 重定向到SSO登录页
用户->>SSO服务端: 输入账号密码登录
SSO服务端->>SSO服务端: 验证用户身份
SSO服务端->>客户端应用: 返回授权码(code)
客户端应用->>SSO服务端: 使用code+ClientSecret换Token
SSO服务端->>Redis存储: 生成并存储Token
SSO服务端->>客户端应用: 返回accessToken+refreshToken
客户端应用->>Redis存储: 缓存Token
客户端应用->>用户: 登录成功,跳转受保护资源
2.3 单点退出创新实现
传统OAuth2.0协议在单点退出场景存在短板,Smart-SSO创新性地设计了"注销通知网络":
flowchart TD
A[用户在客户端A点击退出] --> B[客户端A清除本地Token]
B --> C[调用SSO服务端注销接口]
C --> D[SSO服务端吊销全局会话]
D --> E[查询该用户关联的所有客户端]
E --> F[向所有客户端发送注销通知]
F --> G[各客户端清除本地会话]
G --> H[用户在所有系统同时退出]
三、5分钟极速体验:从0到1搭建SSO服务
3.1 环境准备清单
| 依赖项 | 版本要求 | 说明 |
|---|---|---|
| JDK | 17+ | master分支要求,1.7分支支持JDK8 |
| Maven | 3.6+ | 项目构建工具 |
| MySQL | 8.0+ | 存储用户、权限等核心数据 |
| Redis(可选) | 5.0+ | 分布式部署必选 |
| Git | 2.0+ | 代码拉取工具 |
3.2 服务端部署步骤
# 1. 克隆代码仓库
git clone https://gitcode.com/openjoe/smart-sso.git
cd smart-sso
# 2. 初始化数据库
# 导入db/smart-sso.sql到MySQL
# 修改smart-sso-server/src/main/resources/application.yml中的数据库配置
# 3. 构建项目
mvn clean package -Dmaven.test.skip=true
# 4. 启动服务端
java -jar smart-sso-server/target/smart-sso-server.jar
服务启动成功后,访问 http://localhost:8080 即可看到登录界面,默认管理员账号:admin/123456。
3.3 客户端快速接入(以SpringBoot应用为例)
第一步:添加依赖
<dependency>
<groupId>openjoe.smart.sso</groupId>
<artifactId>smart-sso-starter-client</artifactId>
<version>最新版本</version>
</dependency>
第二步:配置application.yml
smart:
sso:
server-url: http://localhost:8080 # SSO服务端地址
client-id: client1 # 在SSO服务端注册的客户端ID
client-secret: secret1 # 客户端密钥
redirect-uri: http://localhost:8081/client/login # 回调地址
logout-uri: http://localhost:8081/client/logout # 退出地址
第三步:添加注解
@SpringBootApplication
@EnableSSOClient // 启用SSO客户端
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
第四步:配置受保护资源
@RestController
@RequestMapping("/api")
public class ResourceController {
@GetMapping("/userinfo")
@RequiresPermissions("user:view") // 权限控制注解
public Object getUserInfo() {
// 获取当前登录用户信息
return SSOUtils.getCurrentUser();
}
}
第五步:启动客户端应用
java -jar client-app.jar --server.port=8081
访问 http://localhost:8081/api/userinfo 会自动跳转到SSO登录页,登录成功后返回用户信息,整个接入过程不到5行核心代码!
四、高级特性实战:解决企业级复杂场景
4.1 分布式部署方案
当企业用户量增长到一定规模,单节点SSO服务面临性能瓶颈,Smart-SSO提供完整的分布式解决方案:
# 服务端Redis配置
spring:
redis:
host: 192.168.1.100
port: 6379
password: redis_password
smart:
sso:
server:
token-store: redis # 切换为Redis存储Token
redis-prefix: "smart-sso:" # Redis键前缀
客户端同样配置Redis后,多实例部署时Token自动共享,完美支持横向扩展。
4.2 前后端分离架构适配
针对Vue/React等前端框架,Smart-SSO提供无Cookie模式:
// 前端登录示例代码
async function login(username, password) {
// 1. 获取授权码
const code = await fetch(`${ssoServer}/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code`);
// 2. 换取Token
const tokenResponse = await fetch(`${ssoServer}/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `client_id=${clientId}&client_secret=${clientSecret}&code=${code}&grant_type=authorization_code`
});
const { access_token } = await tokenResponse.json();
// 3. 存储Token到localStorage
localStorage.setItem('access_token', access_token);
}
// 发起API请求时携带Token
axios.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${localStorage.getItem('access_token')}`;
return config;
});
4.3 按钮级权限控制实现
Smart-SSO创新性地将权限分为菜单权限和按钮权限两类:
// 后端权限定义示例
@Entity
public class Permission {
private Long id;
private String name; // 权限名称
private String permission; // 权限标识(如:user:view)
private Integer type; // 1-菜单 2-按钮
private String uri; // 请求路径
private String method; // 请求方法(GET/POST等)
// getter/setter省略
}
前端通过获取当前用户权限集合,动态渲染按钮:
<!-- Vue按钮权限控制示例 -->
<template>
<button v-if="hasPermission('user:add')" @click="addUser">新增用户</button>
<button v-if="hasPermission('user:edit')" @click="editUser">编辑用户</button>
<button v-if="hasPermission('user:delete')" @click="deleteUser">删除用户</button>
</template>
<script>
export default {
methods: {
hasPermission(permission) {
return this.$store.state.permissions.includes(permission);
}
}
};
</script>
五、生产环境部署最佳实践
5.1 高可用架构设计
flowchart TD
Client[用户/客户端应用] --> LB[负载均衡器]
LB --> SSO1[SSO服务端实例1]
LB --> SSO2[SSO服务端实例2]
SSO1 <--> Redis[Redis集群]
SSO2 <--> Redis
SSO1 <--> DB[MySQL主从]
SSO2 <--> DB
5.2 安全加固措施
- 传输安全:所有通信采用HTTPS加密
- 密码安全:使用BCrypt算法加密存储密码
- Token安全:
- accessToken有效期设为2小时
- refreshToken有效期设为7天
- 敏感操作需二次验证
- 防CSRF攻击:实现CSRF Token验证
- 接口限流:登录接口限制每分钟5次尝试
5.3 性能优化策略
- 客户端本地缓存:减少80%的服务端校验请求
- Redis连接池优化:
spring: redis: lettuce: pool: max-active: 8 max-idle: 8 min-idle: 2 max-wait: 100ms - 数据库索引优化:关键查询字段建立索引
- 接口响应压缩:启用Gzip压缩
六、常见问题解决方案
6.1 跨域问题排查指南
当遇到跨域问题时,可按以下步骤排查:
- 检查服务端是否配置CorsFilter:
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*"); // 生产环境应限制具体域名
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
- 验证客户端应用配置的redirect-uri是否在SSO服务端白名单中
- 检查浏览器控制台Network标签,查看预检请求(OPTIONS)是否通过
6.2 Token续签失败处理
自动续签失败通常有以下原因:
- refreshToken已过期:此时需引导用户重新登录
- Redis连接异常:检查Redis集群状态
- 客户端时间与服务端不同步:确保服务器时间同步
客户端应实现自动续签失败的降级处理:
// Token自动续签实现
function startTokenRefresh() {
// 在accessToken过期前30分钟开始续签
const refreshInterval = (getTokenExpiry() - 30 * 60 * 1000) - Date.now();
setTimeout(async () => {
try {
const response = await fetch(`${ssoServer}/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `grant_type=refresh_token&refresh_token=${localStorage.getItem('refresh_token')}`
});
if (!response.ok) throw new Error('续签失败');
const { access_token, refresh_token } = await response.json();
localStorage.setItem('access_token', access_token);
localStorage.setItem('refresh_token', refresh_token);
// 继续设置下一次续签
startTokenRefresh();
} catch (error) {
// 续签失败,引导重新登录
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
window.location.href = '/login';
}
}, refreshInterval);
}
七、项目架构与源码解析
7.1 项目目录结构
smart-sso/
├── LICENSE # 开源许可证
├── README.md # 项目说明文档
├── db/ # 数据库脚本
│ └── smart-sso.sql # 初始化SQL脚本
├── smart-sso-demo/ # 客户端示例(传统应用)
├── smart-sso-demo-h5/ # 客户端示例(前后端分离)
├── smart-sso-server/ # 服务端核心模块
│ ├── src/main/java/openjoe/smart/sso/server/
│ │ ├── controller/ # 控制器层
│ │ ├── entity/ # 实体类
│ │ ├── service/ # 服务层
│ │ ├── manager/ </think></think># 【实测封神】Smart-SSO:5分钟搭建企业级单点登录系统,彻底终结多系统账号混乱难题
你是否还在为企业内部10+系统重复登录而抓狂?用户抱怨密码记不住,IT部门疲于账号管理,安全审计更是一团乱麻?今天给大家带来的Smart-SSO开源项目,基于SpringBoot+OAuth2打造,开箱即用的轻量级单点登录解决方案,完美解决跨系统认证难题。**读完本文你将掌握:**
- 3分钟完成SSO服务端部署的实操步骤
- 5行代码实现应用系统接入单点登录
- 分布式环境下的Token共享方案设计
- 前后端分离架构的权限控制最佳实践
- 从0到1搭建企业级认证中心的完整指南
## 一、为什么选择Smart-SSO?市面方案深度横评
企业级单点登录(Single Sign-On,SSO)方案选型一直是架构师的头疼事。我们对当前主流实现方案进行了全方位对比:
| 特性 | 传统Session共享 | JWT令牌 | OAuth2.0标准 | Smart-SSO(OAuth2增强版) |
|---------------------|----------------|-----------------|------------------|--------------------------|
| **单点登录** | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
| **单点退出** | ✅ 需额外开发 | ❌ 难以实现 | ✅ 原生支持 | ✅ 一键退出所有系统 |
| **踢人下线** | ✅ 需额外开发 | ❌ 无法实时失效 | ✅ 需扩展实现 | ✅ 管理员实时管控 |
| **过期自动续签** | ❌ 依赖Cookie | ❌ 需双Token改造 | ✅ 原生支持 | ✅ 无感自动续签 |
| **跨域支持** | ❌ 受浏览器限制 | ✅ 支持 | ✅ 支持 | ✅ 全场景跨域解决方案 |
| **前后端分离** | ❌ 不适用 | ✅ 支持 | ✅ 支持 | ✅ 无Cookie模式优化 |
| **按钮级权限** | ✅ 需定制开发 | ❌ 难以实现 | ❌ 需扩展实现 | ✅ 原生支持API级控制 |
| **分布式部署** | ❌ 集群依赖 | ✅ 支持 | ✅ 需共享存储 | ✅ Redis无缝集群 |
| **性能损耗** | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ 本地缓存优化 |
| **接入复杂度** | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐ | ⭐⭐ 5行代码快速接入 |
**Smart-SSO核心优势**在于:基于OAuth2.0标准协议,却优化了其在企业内部系统的使用痛点。通过客户端本地Token缓存减少80%的服务端请求,独创的"双Token+Redis存根"机制,既保留了JWT的无状态优势,又实现了类似Session的实时管控能力。
## 二、架构解析:Smart-SSO的底层实现原理
### 2.1 核心组件架构
Smart-SSO采用微服务架构设计,主要包含四大模块:
```mermaid
classDiagram
class 服务端模块 {
+认证授权中心
+用户权限管理
+Token生命周期管理
+客户端应用管理
}
class 客户端模块 {
+登录过滤器
+权限过滤器
+Token本地缓存
+自动续签组件
}
class 存储模块 {
+Redis分布式存储
+本地内存缓存
+数据库持久化
}
class 扩展模块 {
+前后端分离支持
+跨域解决方案
+按钮级权限控制
}
服务端模块 <--> 客户端模块 : OAuth2.0协议通信
服务端模块 <--> 存储模块 : Token/权限数据
客户端模块 <--> 存储模块 : 本地缓存
服务端模块 <--> 扩展模块 : 功能扩展点
2.2 单点登录流程(OAuth2.0授权码模式增强版)
sequenceDiagram
participant 用户
participant 客户端应用
participant SSO服务端
participant Redis存储
用户->>客户端应用: 访问受保护资源
客户端应用->>用户: 重定向到SSO登录页
用户->>SSO服务端: 输入账号密码登录
SSO服务端->>SSO服务端: 验证用户身份
SSO服务端->>客户端应用: 返回授权码(code)
客户端应用->>SSO服务端: 使用code+ClientSecret换Token
SSO服务端->>Redis存储: 生成并存储Token
SSO服务端->>客户端应用: 返回accessToken+refreshToken
客户端应用->>Redis存储: 缓存Token
客户端应用->>用户: 登录成功,跳转受保护资源
2.3 单点退出创新实现
传统OAuth2.0协议在单点退出场景存在短板,Smart-SSO创新性地设计了"注销通知网络":
flowchart TD
A[用户在客户端A点击退出] --> B[客户端A清除本地Token]
B --> C[调用SSO服务端注销接口]
C --> D[SSO服务端吊销全局会话]
D --> E[查询该用户关联的所有客户端]
E --> F[向所有客户端发送注销通知]
F --> G[各客户端清除本地会话]
G --> H[用户在所有系统同时退出]
三、5分钟极速体验:从0到1搭建SSO服务
3.1 环境准备清单
| 依赖项 | 版本要求 | 说明 |
|---|---|---|
| JDK | 17+ | master分支要求,1.7分支支持JDK8 |
| Maven | 3.6+ | 项目构建工具 |
| MySQL | 8.0+ | 存储用户、权限等核心数据 |
| Redis(可选) | 5.0+ | 分布式部署必选 |
| Git | 2.0+ | 代码拉取工具 |
3.2 服务端部署步骤
# 1. 克隆代码仓库
git clone https://gitcode.com/openjoe/smart-sso.git
cd smart-sso
# 2. 初始化数据库
# 导入db/smart-sso.sql到MySQL
# 修改smart-sso-server/src/main/resources/application.yml中的数据库配置
# 3. 构建项目
mvn clean package -Dmaven.test.skip=true
# 4. 启动服务端
java -jar smart-sso-server/target/smart-sso-server.jar
服务启动成功后,访问 http://localhost:8080 即可看到登录界面,默认管理员账号:admin/123456。
3.3 客户端快速接入(以SpringBoot应用为例)
第一步:添加依赖
<dependency>
<groupId>openjoe.smart.sso</groupId>
<artifactId>smart-sso-starter-client</artifactId>
<version>最新版本</version>
</dependency>
第二步:配置application.yml
smart:
sso:
server-url: http://localhost:8080 # SSO服务端地址
client-id: client1 # 在SSO服务端注册的客户端ID
client-secret: secret1 # 客户端密钥
redirect-uri: http://localhost:8081/client/login # 回调地址
logout-uri: http://localhost:8081/client/logout # 退出地址
第三步:添加注解
@SpringBootApplication
@EnableSSOClient // 启用SSO客户端
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
第四步:配置受保护资源
@RestController
@RequestMapping("/api")
public class ResourceController {
@GetMapping("/userinfo")
@RequiresPermissions("user:view") // 权限控制注解
public Object getUserInfo() {
// 获取当前登录用户信息
return SSOUtils.getCurrentUser();
}
}
第五步:启动客户端应用
java -jar client-app.jar --server.port=8081
访问 http://localhost:8081/api/userinfo 会自动跳转到SSO登录页,登录成功后返回用户信息,整个接入过程不到5行核心代码!
四、高级特性实战:解决企业级复杂场景
4.1 分布式部署方案
当企业用户量增长到一定规模,单节点SSO服务面临性能瓶颈,Smart-SSO提供完整的分布式解决方案:
# 服务端Redis配置
spring:
redis:
host: 192.168.1.100
port: 6379
password: redis_password
smart:
sso:
server:
token-store: redis # 切换为Redis存储Token
redis-prefix: "smart-sso:" # Redis键前缀
客户端同样配置Redis后,多实例部署时Token自动共享,完美支持横向扩展。
4.2 前后端分离架构适配
针对Vue/React等前端框架,Smart-SSO提供无Cookie模式:
// 前端登录示例代码
async function login(username, password) {
// 1. 获取授权码
const code = await fetch(`${ssoServer}/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code`);
// 2. 换取Token
const tokenResponse = await fetch(`${ssoServer}/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `client_id=${clientId}&client_secret=${clientSecret}&code=${code}&grant_type=authorization_code`
});
const { access_token } = await tokenResponse.json();
// 3. 存储Token到localStorage
localStorage.setItem('access_token', access_token);
}
// 发起API请求时携带Token
axios.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${localStorage.getItem('access_token')}`;
return config;
});
4.3 按钮级权限控制实现
Smart-SSO创新性地将权限分为菜单权限和按钮权限两类:
// 后端权限定义示例
@Entity
public class Permission {
private Long id;
private String name; // 权限名称
private String permission; // 权限标识(如:user:view)
private Integer type; // 1-菜单 2-按钮
private String uri; // 请求路径
private String method; // 请求方法(GET/POST等)
// getter/setter省略
}
前端通过获取当前用户权限集合,动态渲染按钮:
<!-- Vue按钮权限控制示例 -->
<template>
<button v-if="hasPermission('user:add')" @click="addUser">新增用户</button>
<button v-if="hasPermission('user:edit')" @click="editUser">编辑用户</button>
<button v-if="hasPermission('user:delete')" @click="deleteUser">删除用户</button>
</template>
<script>
export default {
methods: {
hasPermission(permission) {
return this.$store.state.permissions.includes(permission);
}
}
};
</script>
五、生产环境部署最佳实践
5.1 高可用架构设计
flowchart TD
Client[用户/客户端应用] --> LB[负载均衡器]
LB --> SSO1[SSO服务端实例1]
LB --> SSO2[SSO服务端实例2]
SSO1 <--> Redis[Redis集群]
SSO2 <--> Redis
SSO1 <--> DB[MySQL主从]
SSO2 <--> DB
5.2 安全加固措施
- 传输安全:所有通信采用HTTPS加密
- 密码安全:使用BCrypt算法加密存储密码
- Token安全:
- accessToken有效期设为2小时
- refreshToken有效期设为7天
- 敏感操作需二次验证
- 防CSRF攻击:实现CSRF Token验证
- 接口限流:登录接口限制每分钟5次尝试
5.3 性能优化策略
- 客户端本地缓存:减少80%的服务端校验请求
- Redis连接池优化:
spring: redis: lettuce: pool: max-active: 8 max-idle: 8 min-idle: 2 max-wait: 100ms - 数据库索引优化:关键查询字段建立索引
- 接口响应压缩:启用Gzip压缩
六、常见问题解决方案
6.1 跨域问题排查指南
当遇到跨域问题时,可按以下步骤排查:
- 检查服务端是否配置CorsFilter:
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*"); // 生产环境应限制具体域名
config.addAllowedMethod("*");
config.addAllowedHeader("*");
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
- 验证客户端应用配置的redirect-uri是否在SSO服务端白名单中
- 检查浏览器控制台Network标签,查看预检请求(OPTIONS)是否通过
6.2 Token续签失败处理
自动续签失败通常有以下原因:
- refreshToken已过期:此时需引导用户重新登录
- Redis连接异常:检查Redis集群状态
- 客户端时间与服务端不同步:确保服务器时间同步
客户端应实现自动续签失败的降级处理:
// Token自动续签实现
function startTokenRefresh() {
// 在accessToken过期前30分钟开始续签
const refreshInterval = (getTokenExpiry() - 30 * 60 * 1000) - Date.now();
setTimeout(async () => {
try {
const response = await fetch(`${ssoServer}/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `grant_type=refresh_token&refresh_token=${localStorage.getItem('refresh_token')}`
});
if (!response.ok) throw new Error('续签失败');
const { access_token, refresh_token } = await response.json();
localStorage.setItem('access_token', access_token);
localStorage.setItem('refresh_token', refresh_token);
// 继续设置下一次续签
startTokenRefresh();
} catch (error) {
// 续签失败,引导重新登录
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
window.location.href = '/login';
}
}, refreshInterval);
}
七、项目架构与源码解析
7.1 项目目录结构
smart-sso/
├── LICENSE # 开源许可证
├── README.md # 项目说明文档
├── db/ # 数据库脚本
│ └── smart-sso.sql # 初始化SQL脚本
├── smart-sso-demo/ # 客户端示例(传统应用)
├── smart-sso-demo-h5/ # 客户端示例(前后端分离)
├── smart-sso-server/ # 服务端核心模块
│ ├── src/main/java/openjoe/smart/sso/server/
│ │ ├── controller/ # 控制器层
│ │ ├── entity/ # 实体类
│ │ ├── service/ # 服务层
│ │ ├── manager/ # 业务管理器
│ │ ├── mapper/ # 数据访问层
│ │ ├── dto/ # 数据传输对象
│ │ ├── enums/ # 枚举定义
│ │ ├── util/ # 工具类
│ │ └── stage/ # 基础框架
└── smart-sso-starter/ # 客户端依赖模块
├── smart-sso-starter-base/ # 基础组件
├── smart-sso-starter-client/ # 客户端核心
├── smart-sso-starter-client-redis/ # 客户端Redis支持
├── smart-sso-starter-server/ # 服务端核心
└── smart-sso-starter-server-redis/ # 服务端Redis支持
7.2 核心代码解析:Token管理器
Token管理器是SSO服务端的核心组件,负责Token的生成、验证和吊销:
@Service
public class TokenManager {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// Token过期时间:2小时
private static final int ACCESS_TOKEN_EXPIRE = 2 * 60 * 60;
// RefreshToken过期时间:7天
private static final int REFRESH_TOKEN_EXPIRE = 7 * 24 * 60 * 60;
/**
* 生成Token
*/
public Token generateToken(User user, App app) {
// 生成Access Token
String accessToken = UUID.randomUUID().toString();
// 生成Refresh Token
String refreshToken = UUID.randomUUID().toString();
// 存储Access Token
String accessTokenKey = "smart-sso:access:" + accessToken;
redisTemplate.opsForValue().set(accessTokenKey,
new TokenContent(user.getId(), app.getId(), user.getUsername()),
ACCESS_TOKEN_EXPIRE, TimeUnit.SECONDS);
// 存储Refresh Token
String refreshTokenKey = "smart-sso:refresh:" + refreshToken;
redisTemplate.opsForValue().set(refreshTokenKey,
new RefreshTokenContent(user.getId(), app.getId(), accessToken),
REFRESH_TOKEN_EXPIRE, TimeUnit.SECONDS);
return new Token(accessToken, refreshToken, ACCESS_TOKEN_EXPIRE);
}
/**
* 验证Token
*/
public TokenContent validateToken(String accessToken) {
String key = "smart-sso:access:" + accessToken;
TokenContent content = (TokenContent) redisTemplate.opsForValue().get(key);
if (content == null) {
throw new InvalidTokenException("Token已过期或无效");
}
// 自动续期:当Token剩余时间不足30分钟时,延长有效期
Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);
if (expire < 30 * 60) {
redisTemplate.expire(key, ACCESS_TOKEN_EXPIRE, TimeUnit.SECONDS);
}
return content;
}
/**
* 吊销用户所有Token
*/
public void revokeUserTokens(Long userId) {
Set<String> keys = redisTemplate.keys("smart-sso:access:*");
for (String key : keys) {
TokenContent content = (TokenContent) redisTemplate.opsForValue().get(key);
if (content != null && content.getUserId().equals(userId)) {
redisTemplate.delete(key);
}
}
// 同时删除相关的RefreshToken
Set<String> refreshKeys = redisTemplate.keys("smart-sso:refresh:*");
for (String key : refreshKeys) {
RefreshTokenContent content = (RefreshTokenContent) redisTemplate.opsForValue().get(key);
if (content != null && content.getUserId().equals(userId)) {
redisTemplate.delete(key);
}
}
}
}
八、总结与展望
Smart-SSO作为一款企业级单点登录解决方案,凭借其轻量级设计、丰富功能和易于扩展的特性,已在多家企业的生产环境中得到验证。相比商业SSO产品动辄数十万的授权费用,Smart-SSO完全开源免费,却提供了80%的企业所需功能。
未来 roadmap:
- 集成OAuth2.1协议支持
- 增加多因素认证(MFA)
- 实现与LDAP/Active Directory集成
- 开发更丰富的客户端SDK(Python/Go等)
如果你正在为企业寻找一款开箱即用的SSO解决方案,Smart-SSO绝对值得一试。项目源码已托管在Gitcode:https://gitcode.com/openjoe/smart-sso,欢迎Star收藏,也期待你的贡献!
GLM-5智谱 AI 正式发布 GLM-5,旨在应对复杂系统工程和长时域智能体任务。Jinja00
LongCat-AudioDiT-1BLongCat-AudioDiT 是一款基于扩散模型的文本转语音(TTS)模型,代表了当前该领域的最高水平(SOTA),它直接在波形潜空间中进行操作。00
jiuwenclawJiuwenClaw 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。Python0248- QQwen3.5-397B-A17BQwen3.5 实现了重大飞跃,整合了多模态学习、架构效率、强化学习规模以及全球可访问性等方面的突破性进展,旨在为开发者和企业赋予前所未有的能力与效率。Jinja00
AtomGit城市坐标计划AtomGit 城市坐标计划开启!让开源有坐标,让城市有星火。致力于与城市合伙人共同构建并长期运营一个健康、活跃的本地开发者生态。01
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python05