一、Sa-Token-SSO 简介
Sa-Token-SSO 由简入难划分为三种模式,解决不同架构下的 SSO 接入问题:
系统架构 | 采用模式 | 简介 |
---|---|---|
前端同域 + 后端同 Redis | 模式一 | 共享 Cookie 同步会话 |
前端不同域 + 后端同 Redis | 模式二 | URL重定向传播会话 |
前端不同域 + 后端不同 Redis | 模式三 | Http请求获取会话 |
二、搭建统一认证中心 SSO-Server
1、添加依赖
创建 SpringBoot 项目 sa-token-demo-sso-server,引入依赖:
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.38.0</version>
</dependency>
<!-- Sa-Token 插件:整合SSO -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-sso</artifactId>
<version>1.38.0</version>
</dependency>
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>1.38.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- 视图引擎(在前后端不分离模式下提供视图支持) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Http请求工具(在模式三的单点注销功能下用到,如不需要可以注释掉) -->
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>forest-spring-boot-starter</artifactId>
<version>1.5.26</version>
</dependency>
2、开放认证接口
新建 SsoServerController,用于对外开放接口:
/**
* Sa-Token-SSO Server端 Controller
*/
@RestController
public class SsoServerController {
/**
* SSO-Server端:处理所有SSO相关请求 (下面的章节我们会详细列出开放的接口)
*/
@RequestMapping("/sso/*")
public Object ssoRequest() {
return SaSsoServerProcessor.instance.dister();
}
/**
* 配置SSO相关参数
*/
@Autowired
private void configSso(SaSsoServerConfig ssoServer) {
// 配置:未登录时返回的View
ssoServer.notLoginView = () -> {
String msg = "当前会话在SSO-Server端尚未登录,请先访问"
+ "<a href='/sso/doLogin?name=sa&pwd=123456' target='_blank'> doLogin登录 </a>"
+ "进行登录之后,刷新页面开始授权";
return msg;
};
// 配置:登录处理函数
ssoServer.doLoginHandle = (name, pwd) -> {
// 此处仅做模拟登录,真实环境应该查询数据进行登录
if("sa".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001);
return SaResult.ok("登录成功!").setData(StpUtil.getTokenValue());
}
return SaResult.error("登录失败!");
};
// 配置 Http 请求处理器 (在模式三的单点注销功能下用到,如不需要可以注释掉)
ssoServer.sendHttp = url -> {
try {
System.out.println("------ 发起请求:" + url);
String resStr = Forest.get(url).executeAsString();
System.out.println("------ 请求结果:" + resStr);
return resStr;
} catch (Exception e) {
e.printStackTrace();
return null;
}
};
}
}
全局异常处理:
@RestControllerAdvice
public class GlobalExceptionHandler {
// 全局异常拦截
@ExceptionHandler
public SaResult handlerException(Exception e) {
e.printStackTrace();
return SaResult.error(e.getMessage());
}
}
3、application.yml配置
# 端口
server:
port: 9000
# Sa-Token 配置
sa-token:
# ------- SSO-模式一相关配置 (非模式一不需要配置)
# cookie:
# 配置 Cookie 作用域
# domain: stp.com
# ------- SSO-模式二相关配置
sso-server:
# Ticket有效期 (单位: 秒),默认五分钟
ticket-timeout: 300
# 所有允许的授权回调地址
allow-url: "*"
# ------- SSO-模式三相关配置 (下面的配置在使用SSO模式三时打开)
# 是否打开模式三
is-http: true
sign:
# API 接口调用秘钥
secret-key: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor
# ---- 除了以上配置项,你还需要为 Sa-Token 配置http请求处理器(文档有步骤说明)
spring:
# Redis配置 (SSO模式一和模式二使用Redis来同步会话)
redis:
# Redis数据库索引(默认为0)
database: 1
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
forest:
# 关闭 forest 请求日志打印
log-enabled: false
4、创建启动类
@SpringBootApplication
public class SaSsoServerApplication {
public static void main(String[] args) {
SpringApplication.run(SaSsoServerApplication.class, args);
System.out.println();
System.out.println("---------------------- Sa-Token SSO 统一认证中心启动成功 ----------------------");
System.out.println("配置信息:" + SaSsoManager.getServerConfig());
System.out.println();
}
}
访问统一授权地址(仅测试 SSO-Server 是否部署成功,暂时还不需要点击登录):
http://localhost:9000/sso/auth
三、SSO 客户端搭建-URL重定向传播会话
如果我们的多个系统:部署在不同的域名之下,但是后端可以连接同一个Redis,那么便可以使用 URL重定向传播会话
的方式做到单点登录。
1. 单点登录流程
- 用户在 子系统 点击 [登录] 按钮。
- 用户跳转到子系统登录接口 /sso/login,并携带 back参数 记录初始页面URL。
形如:http://{sso-client}/sso/login?back=xxx - 子系统检测到此用户尚未登录,再次将其重定向至SSO认证中心,并携带redirect参数记录子系统的登录页URL。
形如:http://{sso-server}/sso/auth?redirect=xxx?back=xxx - 用户进入了 SSO认证中心 的登录页面,开始登录。
- 用户 输入账号密码 并 登录成功,SSO认证中心再次将用户重定向至子系统的登录接口/sso/login,并携带ticket码参数。
形如:http://{sso-client}/sso/login?back=xxx&ticket=xxxxxxxxx - 子系统根据 ticket码 从 SSO-Redis 中获取账号id,并在子系统登录此账号会话。
子系统将用户再次重定向至最初始的 back 页面。
2. 搭建 Client 端项目
搭建示例在官方仓库的 /sa-token-demo/sa-token-demo-sso/sa-token-demo-sso2-client/,如遇到难点可结合源码进行测试学习
2.1 引入 pom 依赖
<!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.38.0</version>
</dependency>
<!-- Sa-Token 插件:整合SSO -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-sso</artifactId>
<version>1.38.0</version>
</dependency>
<!-- Sa-Token 整合redis (使用jackson序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>1.38.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- Sa-Token插件:权限缓存与业务缓存分离 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-alone-redis</artifactId>
<version>1.38.0</version>
</dependency>
2.2 创建 SSO-Client 端认证接口
同 SSO-Server 一样,Sa-Token 为 SSO-Client 端所需代码也提供了完整的封装,你只需提供一个访问入口,接入 Sa-Token 的方法即可。
/**
* Sa-Token-SSO Client端 Controller
*/
@RestController
public class SsoClientController {
// 首页
@RequestMapping("/")
public String index() {
String str = "<h2>Sa-Token SSO-Client 应用端</h2>" +
"<p>当前会话是否登录:" + StpUtil.isLogin() + "</p>" +
"<p><a href=\"javascript:location.href='/sso/login?back=' + encodeURIComponent(location.href);\">登录</a> " +
"<a href='/sso/logout?back=self'>注销</a></p>";
return str;
}
/*
* SSO-Client端:处理所有SSO相关请求
* http://{host}:{port}/sso/login -- Client端登录地址,接受参数:back=登录后的跳转地址
* http://{host}:{port}/sso/logout -- Client端单点注销地址(isSlo=true时打开),接受参数:back=注销后的跳转地址
* http://{host}:{port}/sso/logoutCall -- Client端单点注销回调地址(isSlo=true时打开),此接口为框架回调,开发者无需关心
*/
@RequestMapping("/sso/*")
public Object ssoRequest() {
return SaSsoClientProcessor.instance.dister();
}
}
2.3 配置SSO认证中心地址
# 端口
server:
port: 9001
# sa-token配置
sa-token:
# SSO-相关配置
sso-client:
# SSO-Server 端主机地址
server-url: http://sa-sso-server.com:9000
# 配置Sa-Token单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis)
alone-redis:
# Redis数据库索引 (默认为0)
database: 1
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
# 连接超时时间
timeout: 10s
2.4 写启动类
@SpringBootApplication
public class SaSso2ClientApplication {
public static void main(String[] args) {
SpringApplication.run(SaSso2ClientApplication.class, args);
System.out.println();
System.out.println("---------------------- Sa-Token SSO 模式二 Client 端启动成功 ----------------------");
System.out.println("配置信息:" + SaSsoManager.getClientConfig());
System.out.println("测试访问应用端一: http://sa-sso-client1.com:9001");
System.out.println("测试访问应用端二: http://sa-sso-client2.com:9001");
System.out.println("测试访问应用端三: http://sa-sso-client3.com:9001");
System.out.println("测试前需要根据官网文档修改hosts文件,测试账号密码:sa / 123456");
System.out.println();
}
}
2.5 测试访问
依次启动 SSO-Server 与 SSO-Client,然后从浏览器访问:http://sa-sso-client1.com:9001/
参考:https://sa-token.cc/doc.html#/sso/sso-type2