优化SSO相关文档

This commit is contained in:
click33
2021-08-24 02:05:16 +08:00
parent 5294b23652
commit bcc1e0cc93
19 changed files with 407 additions and 342 deletions

View File

@@ -15,13 +15,13 @@ sa-token:
# Redis数据库索引默认为0
database: 2
# Redis服务器地址
host: 127.0.0.1
host: 49.235.117.153
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码默认为空
password:
password: Kdfsjia.d.1212dsa
# 连接超时时间(毫秒)
timeout: 10ms
timeout: 10s
lettuce:
pool:
# 连接池最大连接数
@@ -45,7 +45,7 @@ spring:
# Redis服务器连接密码默认为空
password:
# 连接超时时间(毫秒)
timeout: 10ms
timeout: 10s
lettuce:
pool:
# 连接池最大连接数

View File

@@ -30,8 +30,8 @@ spring:
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间(毫秒)
timeout: 10ms
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池最大连接数

View File

@@ -21,8 +21,8 @@ sa-token:
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间(毫秒)
timeout: 10ms
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池最大连接数

View File

@@ -23,8 +23,8 @@ spring:
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间(毫秒)
timeout: 10ms
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池最大连接数

View File

@@ -32,8 +32,8 @@ spring:
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间(毫秒)
timeout: 10ms
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池最大连接数

View File

@@ -29,8 +29,8 @@ spring:
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间(毫秒)
timeout: 10ms
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池最大连接数

View File

@@ -19,7 +19,7 @@
为了保证新同学不迷路,请允许我唠叨一下:无论您从何处看到本篇文章,最新开发文档永远在:[http://sa-token.dev33.cn/](http://sa-token.dev33.cn/)
建议收藏在浏览器书签,如果您已经身处本网站下,则请忽略此条说明。
用心阅读文档,你学习到的将不止是 `Sa-Token` 框架本身,更是绝大多数场景下权限设计的最佳实践。
本文档将会尽力讲解每个功能的设计原因、应用场景,用心阅读文档,你学习到的将不止是 `Sa-Token` 框架本身,更是绝大多数场景下权限设计的最佳实践。
## Sa-Token 介绍
**Sa-Token** 是一个轻量级 Java 权限认证框架,主要解决:**`登录认证`**、**`权限认证`**、**`Session会话`**、**`单点登录`**、**`OAuth2.0`**、**`微服务网关鉴权`**

View File

@@ -36,7 +36,11 @@
- [SSO模式一 共享Cookie同步会话](/sso/sso-type1)
- [SSO模式二 URL重定向传播会话](/sso/sso-type2)
- [SSO模式三 Http请求获取会话](/sso/sso-type3)
- [SSO整合-常见问题总结](/sso/sso-cd)
- [SSO整合:配置域名校验](/sso/sso-check-domain)
- [SSO整合定制化登录页面](/sso/sso-custom-login)
- [SSO整合前后端分离下的整合方案](/sso/sso-h5)
- [SSO整合常见问题总结](/sso/sso-questions)
- [Sa-Sso-Pro单点登录商业版](/sso/sso-pro)
- **OAuth2.0**
- [OAuth2.0简述](/oauth2/readme)

View File

@@ -71,7 +71,7 @@
// basePath: '/sa-token-doc/', // 设置文件加载的父路径, 这在一些带项目名部署的文件中非常有效
auto2top: true, // 是否在切换页面后回到顶部
// coverpage: true, // 开启封面
subMaxLevel: 3, // 标题解析层级, 写几就在目录树中解析到几级标题 ,一般写2吧也就
subMaxLevel: 4, // 标题解析层级, 写几就在目录树中解析到几级标题 ,一般写2吧也就
loadSidebar: true, // 加载自定义侧边栏 , 目录定制在: _sidebar.md 文件 (需要创建 .nojekyll 的空文件,阻止 GitHub Pages 忽略命名是下划线开头的文件)
copyCode: { // 复制插件
buttonText: '复制到剪贴板',

View File

@@ -8,6 +8,7 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu
#main h3 {font-size: 1.25rem;}
.main-box .markdown-section{ padding: 30px 20px; max-width: 75%; margin-left: 10%;}
.main-box .markdown-section h4{font-size: 1rem;}
@media screen and (max-width: 800px) {
.logo-box {display: none;}
.main-box .markdown-section{max-width: 1000px; margin-left: auto;}

View File

@@ -33,7 +33,7 @@ sa-token:
# Token风格
token-style: uuid
# 配置Sa-Token单独使用的Redis连接
# 配置 Sa-Token 单独使用的 Redis 连接
alone-redis:
# Redis数据库索引默认为0
database: 2
@@ -43,11 +43,11 @@ sa-token:
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间(毫秒)
timeout: 10ms
# 连接超时时间
timeout: 10s
spring:
# 配置业务使用的Redis连接
# 配置业务使用的 Redis 连接
redis:
# Redis数据库索引默认为0
database: 0
@@ -57,8 +57,8 @@ spring:
port: 6379
# Redis服务器连接密码默认为空
password:
# 连接超时时间(毫秒)
timeout: 10ms
# 连接超时时间
timeout: 10s
```
具体可参考示例:[码云application.yml](https://gitee.com/dromara/sa-token/blob/dev/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml)

View File

@@ -1,12 +0,0 @@
<!-- 这是目录树文件 -->
- **单点登录**
- [单点登录简述](/sso/readme)
- [SSO模式一 共享Cookie同步会话](/sso/sso-type1)
- [SSO模式二 URL重定向传播会话](/sso/sso-type2)
- [SSO模式三 Http请求获取会话](/sso/sso-type3)
<!-- <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<p style="text-align: center; ">----- 到底线了 -----</p> -->

View File

@@ -1,263 +0,0 @@
# Sa-Token-SSO整合-常见问题总结
---
### 一、何时引导用户去登录?
以下方案三选一:
##### 1.1、前端按钮跳转
前端页面准备一个**`[登录]`**按钮,当用户点击按钮时,跳转到登录接口
``` js
<a href="javascript:location.href='/sso/login?back=' + encodeURIComponent(location.href);">登录</a>
```
##### 1.2、后端拦截重定向
在后端注册全局过滤器(或拦截器、或全局异常处理),拦截需要登录后才能访问的页面资源,将未登录的访问重定向至登录接口
``` java
/**
* Sa-Token 配置类
*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
/** 注册 [Sa-Token全局过滤器] */
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
.addInclude("/**")
.addExclude("/sso/*", "/favicon.ico")
.setAuth(r -> {
if(StpUtil.isLogin() == false) {
String back = SaFoxUtil.joinParam(SaHolder.getRequest().getUrl(), SpringMVCUtil.getRequest().getQueryString());
SaHolder.getResponse().redirect("/sso/login?back=" + SaFoxUtil.encodeUrl(back));
SaRouter.back();
}
})
;
}
}
```
##### 1.3、后端拦截 + 前端跳转
首先,后端仍需要提供拦截,但是不直接引导用户重定向,而是返回未登录的提示信息
``` java
/**
* Sa-Token 配置类
*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
/** 注册 [Sa-Token全局过滤器] */
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
.addInclude("/**")
.addExclude("/sso/*", "/favicon.ico")
.setAuth(r -> {
if(StpUtil.isLogin() == false) {
// 与前端约定好code=401时代表会话未登录
SaRouter.back(SaResult.ok().setCode(401));
}
})
;
}
}
```
前端接受到返回结果 `code=401` 时,开始跳转至登录接口
``` js
if(res.code == 401) {
location.href = '/sso/login?back=' + encodeURIComponent(location.href);
}
```
这种方案比较适合以 Ajax 访问的 RestAPI 接口重定向
### 二、如何自定义登录视图?
- 方式一在demo示例中直接更改页面代码
- 方式二:在配置中配置登录视图地址
``` java
cfg.sso
// 配置未登录时返回的View
.setNotLoginView(() -> {
return new ModelAndView("xxx.html");
})
```
### 三、如何自定义登录API的接口
根据需求点选择解决方案:
##### 3.1、如果只是想在 setDoLoginHandle 函数里获取除 name、pwd 以外的参数?
``` java
// 在任意代码处获取前端提交的参数
String xxx = SaHolder.getRequest().getParam("xxx");
```
##### 3.2、想完全自定义一个接口来接受前端登录请求?
``` java
// 直接定义一个拦截路由为 `/sso/doLogin` 的接口即可
@RequestMapping("/sso/doLogin")
public SaResult ss(String name, String pwd) {
System.out.println("------ 请求进入了自定义的API接口 ---------- ");
if("sa".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001);
return SaResult.ok("登录成功!");
}
return SaResult.error("登录失败!");
}
```
##### 3.3、不想使用`/sso/doLogin`这个接口想自定义一个API地址
答:直接在前端更改点击按钮时 Ajax 的请求地址即可
### 四、前后端分离架构下的整合方案
如果我们已有的系统是前后端分离模式我们显然不能为了接入SSO而改造系统的基础架构官方仓库的示例采用的是前后端一体方案要将其改造为前后台分离架构模式非常简单
以`sa-token-demo-sso2-client`为例:
##### 4.1、新建`H5Controller`开放接口
``` java
/**
* 前后台分离架构下集成SSO所需的代码
*/
@RestController
public class H5Controller {
// 当前是否登录
@RequestMapping("/isLogin")
public Object isLogin() {
return SaResult.data(StpUtil.isLogin());
}
// 返回SSO认证中心登录地址
@RequestMapping("/getSsoAuthUrl")
public SaResult getSsoAuthUrl(String clientLoginUrl) {
String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(clientLoginUrl, "");
return SaResult.data(serverAuthUrl);
}
// 根据ticket进行登录
@RequestMapping("/doLoginByTicket")
public SaResult doLoginByTicket(String ticket) {
Object loginId = checkTicket(ticket);
if(loginId != null) {
StpUtil.login(loginId);
return SaResult.data(StpUtil.getTokenValue());
}
return SaResult.error("无效ticket" + ticket);
}
// 校验 Ticket码获取账号Id
private Object checkTicket(String ticket) {
return SaSsoUtil.checkTicket(ticket);
}
// 全局异常拦截
@ExceptionHandler
public SaResult handlerException(Exception e) {
e.printStackTrace();
return SaResult.error(e.getMessage());
}
}
```
##### 4.2、增加跨域过滤器`CorsFilter.java`
源码详见:[CorsFilter.java](https://gitee.com/dromara/sa-token/tree/master/sa-token-demo/sa-token-demo-sso2-client/src/main/java/com/pj/h5/CorsFilter.java)
将其复制到项目中即可
##### 4.3、新建前端项目
任意文件夹新建前端项目:`sa-token-demo-sso2-client-h5`,在根目录添加测试文件:`index.html`
``` js
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sa-Token-SSO-Client端-测试页(前后端分离版)</title>
</head>
<body>
<h2>Sa-Token SSO-Client 应用端(前后端分离版)</h2>
<p>当前是否登录:<b class="is-login"></b></p>
<p>
<a href="javascript:location.href='sso-login.html?back=' + encodeURIComponent(location.href);">登录</a>
<a href="javascript:location.href=baseUrl + '/sso/logout?satoken=' + localStorage.satoken + '&back=' + encodeURIComponent(location.href);">注销</a>
</p>
<script src="https://unpkg.zhimg.com/jquery@3.4.1/dist/jquery.min.js"></script>
<script type="text/javascript">
// 后端接口地址
var baseUrl = "http://sa-sso-client1.com:9001";
// 查询当前会话是否登录
$.ajax({
url: baseUrl + '/isLogin',
type: "post",
dataType: 'json',
headers: {
"X-Requested-With": "XMLHttpRequest",
"satoken": localStorage.getItem("satoken")
},
success: function(res){
$('.is-login').html(res.data + '');
},
error: function(xhr, type, errorThrown){
return alert("异常:" + JSON.stringify(xhr));
}
});
</script>
</body>
</html>
```
##### 4.4、添加登录处理文件`sso-login.html`
源码详见:[sso-login.html](https://gitee.com/dromara/sa-token/tree/master/sa-token-demo/sa-token-demo-sso2-client-h5/sso-login.html)
将其复制到项目中即可,与`index.html`一样放在根目录下
##### 4.5、测试运行
先启动Server服务端与Client服务端再随便找个能预览html的工具打开前端项目比如[HBuilderX](https://www.dcloud.io/hbuilderx.html)),测试流程与一体版一致
##### 4.6、疑问我在SSO模式三的demo中加入上述代码提示我ticket无效是怎么回事
上述代码是以SSO模式二为基础的提示“Ticket无效”的原因很简单因为SSO模式三种 Server端 与 Client端 连接的不是同一个Redis
所以Client端校验Ticket时无法在Redis中查询到相应的值才会产生异常“Ticket无效”
要使上述代码生效很简单我们只需更改一下校验Ticket的逻辑即可将 `H5Controller` 中的 `checkTicket` 方法代码改为:
``` java
// 校验 Ticket码获取账号Id
private Object checkTicket(String ticket) {
SaSsoConfig cfg = SaManager.getConfig().getSso();
String ssoLogoutCall = null;
if(cfg.isSlo) {
ssoLogoutCall = SaHolder.getRequest().getUrl().replace("/doLoginByTicket", Api.ssoLogoutCall);
}
String checkUrl = SaSsoUtil.buildCheckTicketUrl(ticket, ssoLogoutCall);
Object body = cfg.sendHttp.apply(checkUrl);
return (SaFoxUtil.isEmpty(body) ? null : body);
}
```
重新运行项目即可在SSO模式三中成功整合前后台分离模式 。
### 五、常见疑问
##### 问在模式一与模式二中Client端 必须通过 Alone-Redis 插件来访问Redis吗
不必须只是推荐权限缓存与业务缓存分离后会减少SSO-Redis的访问压力且可以避免多个Client端的缓存读写冲突
##### 问:将旧有系统改造为单点登录时,应该注意哪些?
建议不要把其中一个系统改造为SSO服务端而是新起一个项目作为Server端所有旧有项目全部作为Client端与此对接

View File

@@ -0,0 +1,43 @@
# SSO整合-配置域名校验
---
### 1、Ticket劫持攻击
在前面章节的 SSO-Server 示例中,配置项 `sa-token.sso.allow-url=*` 意为配置所有允许的Client端授权地址不在此配置项中的URL将无法单点登录成功
为了方便测试,上述代码将其配置为`*`,但是,<font color="#FF0000" >在生产环境中,此配置项绝对不能配置为 * </font>,否则会有被 Ticket 劫持的风险
假设攻击者根据模仿我们的授权地址巧妙的构造一个URL
> [http://sa-sso-server.com:9000/sso/auth?redirect=https://www.baidu.com/](http://sa-sso-server.com:9000/sso/auth?redirect=https://www.baidu.com/)
当不知情的小红被诱导访问了这个URL时它将被重定向至百度首页
![sso-ticket-jc](https://oss.dev33.cn/sa-token/doc/sso/sso-ticket-jc.png 's-w-sh')
可以看到,代表着用户身份的 Ticket 码也显现到了URL之中借此漏洞攻击者完全可以构建一个URL将小红的 Ticket 码自动提交到攻击者自己的服务器,伪造小红身份登录网站
### 2、防范方法
造成此漏洞的直接原因就是SSO-Server认证中心没有对 `redirect地址` 进行任何的限制,防范的方法也很简单,就是对`redirect参数`进行校验如果其不在指定的URL列表中时拒绝下放ticket
我们将其配置为一个具体的URL`allow-url=http://sa-sso-client1.com:9001/sso/login`,再次访问上述连接:
![sso-feifa-rf](https://oss.dev33.cn/sa-token/doc/sso/sso-feifa-rf.png 's-w-sh')
域名没有通过校验,拒绝授权!
### 3、配置安全性参考表
| 配置方式 | 举例 | 安全性 | 建议 |
| :-------- | :-------- | :-------- | :-------- |
| 配置为* | `*` | <font color="#F00" ></font> | **<font color="#F00" >禁止在生产环境下使用</font>** |
| 配置到域名 | `http://sa-sso-client1.com/*` | <font color="#F70" ></font> | <font color="#F70" >不建议在生产环境下使用</font> |
| 配置到详细地址| `http://sa-sso-client1.com:9001/sso/login` | <font color="#080" ></font> | <font color="#080" >可以在生产环境下使用</font> |
### 4、疑问为什么不直接回传 Token而是先回传 Ticket再用 Ticket 去查询对应的账号id
Token 作为长时间有效的会话凭证,在任何时候都不应该直接暴露在 URL 之中(虽然 Token 直接的暴露本身不会造成安全漏洞,但会为很多漏洞提供可乘之机)
因此 Sa-Token-SSO 选择先回传 Ticket再由 Ticket 获取账号id且 Ticket 一次性用完即废,提高安全性

View File

@@ -0,0 +1,117 @@
# SSO整合-定制化登录页面
---
### 1、何时引导用户去登录
#### 方案一:前端按钮跳转
前端页面准备一个**`[登录]`**按钮,当用户点击按钮时,跳转到登录接口
``` js
<a href="javascript:location.href='/sso/login?back=' + encodeURIComponent(location.href);">登录</a>
```
#### 方案二:后端拦截重定向
在后端注册全局过滤器(或拦截器、或全局异常处理),拦截需要登录后才能访问的页面资源,将未登录的访问重定向至登录接口
``` java
/**
* Sa-Token 配置类
*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
/** 注册 [Sa-Token全局过滤器] */
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
.addInclude("/**")
.addExclude("/sso/*", "/favicon.ico")
.setAuth(r -> {
if(StpUtil.isLogin() == false) {
String back = SaFoxUtil.joinParam(SaHolder.getRequest().getUrl(), SpringMVCUtil.getRequest().getQueryString());
SaHolder.getResponse().redirect("/sso/login?back=" + SaFoxUtil.encodeUrl(back));
SaRouter.back();
}
})
;
}
}
```
#### 方案三:后端拦截 + 前端跳转
首先,后端仍需要提供拦截,但是不直接引导用户重定向,而是返回未登录的提示信息
``` java
/**
* Sa-Token 配置类
*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
/** 注册 [Sa-Token全局过滤器] */
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
.addInclude("/**")
.addExclude("/sso/*", "/favicon.ico")
.setAuth(r -> {
if(StpUtil.isLogin() == false) {
// 与前端约定好code=401时代表会话未登录
SaRouter.back(SaResult.ok().setCode(401));
}
})
;
}
}
```
前端接受到返回结果 `code=401` 时,开始跳转至登录接口
``` js
if(res.code == 401) {
location.href = '/sso/login?back=' + encodeURIComponent(location.href);
}
```
这种方案比较适合以 Ajax 访问的 RestAPI 接口重定向
### 2、如何自定义登录视图
#### 方式一在demo示例中直接更改 login.html 页面代码即可
#### 方式二:在配置中配置登录视图地址
``` java
cfg.sso
// 配置未登录时返回的View
.setNotLoginView(() -> {
return new ModelAndView("xxx.html");
})
```
### 3、如何自定义登录API的接口
根据需求点选择解决方案:
#### 3.1、如果只是想在 setDoLoginHandle 函数里获取除 name、pwd 以外的参数?
``` java
// 在任意代码处获取前端提交的参数
String xxx = SaHolder.getRequest().getParam("xxx");
```
#### 3.2、想完全自定义一个接口来接受前端登录请求?
``` java
// 直接定义一个拦截路由为 `/sso/doLogin` 的接口即可
@RequestMapping("/sso/doLogin")
public SaResult ss(String name, String pwd) {
System.out.println("------ 请求进入了自定义的API接口 ---------- ");
if("sa".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001);
return SaResult.ok("登录成功!");
}
return SaResult.error("登录失败!");
}
```
#### 3.3、不想使用`/sso/doLogin`这个接口想自定义一个API地址
答:直接在前端更改点击按钮时 Ajax 的请求地址即可

View File

@@ -0,0 +1,135 @@
# SSO整合-前后端分离架构下的整合方案
---
如果我们已有的系统是前后端分离模式我们显然不能为了接入SSO而改造系统的基础架构官方仓库的示例采用的是前后端一体方案要将其改造为前后台分离架构模式非常简单
`sa-token-demo-sso2-client`为例:
### 1、新建`H5Controller`开放接口
``` java
/**
* 前后台分离架构下集成SSO所需的代码
*/
@RestController
public class H5Controller {
// 当前是否登录
@RequestMapping("/isLogin")
public Object isLogin() {
return SaResult.data(StpUtil.isLogin());
}
// 返回SSO认证中心登录地址
@RequestMapping("/getSsoAuthUrl")
public SaResult getSsoAuthUrl(String clientLoginUrl) {
String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(clientLoginUrl, "");
return SaResult.data(serverAuthUrl);
}
// 根据ticket进行登录
@RequestMapping("/doLoginByTicket")
public SaResult doLoginByTicket(String ticket) {
Object loginId = checkTicket(ticket);
if(loginId != null) {
StpUtil.login(loginId);
return SaResult.data(StpUtil.getTokenValue());
}
return SaResult.error("无效ticket" + ticket);
}
// 校验 Ticket码获取账号Id
private Object checkTicket(String ticket) {
return SaSsoUtil.checkTicket(ticket);
}
// 全局异常拦截
@ExceptionHandler
public SaResult handlerException(Exception e) {
e.printStackTrace();
return SaResult.error(e.getMessage());
}
}
```
### 2、增加跨域过滤器`CorsFilter.java`
源码详见:[CorsFilter.java](https://gitee.com/dromara/sa-token/tree/master/sa-token-demo/sa-token-demo-sso2-client/src/main/java/com/pj/h5/CorsFilter.java)
将其复制到项目中即可
### 3、新建前端项目
任意文件夹新建前端项目:`sa-token-demo-sso2-client-h5`,在根目录添加测试文件:`index.html`
``` js
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sa-Token-SSO-Client端-测试页(前后端分离版)</title>
</head>
<body>
<h2>Sa-Token SSO-Client 应用端(前后端分离版)</h2>
<p>当前是否登录:<b class="is-login"></b></p>
<p>
<a href="javascript:location.href='sso-login.html?back=' + encodeURIComponent(location.href);">登录</a>
<a href="javascript:location.href=baseUrl + '/sso/logout?satoken=' + localStorage.satoken + '&back=' + encodeURIComponent(location.href);">注销</a>
</p>
<script src="https://unpkg.zhimg.com/jquery@3.4.1/dist/jquery.min.js"></script>
<script type="text/javascript">
// 后端接口地址
var baseUrl = "http://sa-sso-client1.com:9001";
// 查询当前会话是否登录
$.ajax({
url: baseUrl + '/isLogin',
type: "post",
dataType: 'json',
headers: {
"X-Requested-With": "XMLHttpRequest",
"satoken": localStorage.getItem("satoken")
},
success: function(res){
$('.is-login').html(res.data + '');
},
error: function(xhr, type, errorThrown){
return alert("异常:" + JSON.stringify(xhr));
}
});
</script>
</body>
</html>
```
### 4、添加登录处理文件`sso-login.html`
源码详见:[sso-login.html](https://gitee.com/dromara/sa-token/tree/master/sa-token-demo/sa-token-demo-sso2-client-h5/sso-login.html)
将其复制到项目中即可,与`index.html`一样放在根目录下
### 5、测试运行
先启动Server服务端与Client服务端再随便找个能预览html的工具打开前端项目比如[HBuilderX](https://www.dcloud.io/hbuilderx.html)),测试流程与一体版一致
### 6、疑问我在SSO模式三的demo中加入上述代码提示我ticket无效是怎么回事
上述代码是以SSO模式二为基础的提示“Ticket无效”的原因很简单因为SSO模式三种 Server端 与 Client端 连接的不是同一个Redis
所以Client端校验Ticket时无法在Redis中查询到相应的值才会产生异常“Ticket无效”
要使上述代码生效很简单我们只需更改一下校验Ticket的逻辑即可将 `H5Controller` 中的 `checkTicket` 方法代码改为:
``` java
// 校验 Ticket码获取账号Id
private Object checkTicket(String ticket) {
SaSsoConfig cfg = SaManager.getConfig().getSso();
String ssoLogoutCall = null;
if(cfg.isSlo) {
ssoLogoutCall = SaHolder.getRequest().getUrl().replace("/doLoginByTicket", Api.ssoLogoutCall);
}
String checkUrl = SaSsoUtil.buildCheckTicketUrl(ticket, ssoLogoutCall);
Object body = cfg.sendHttp.apply(checkUrl);
return (SaFoxUtil.isEmpty(body) ? null : body);
}
```
重新运行项目即可在SSO模式三中成功整合前后台分离模式 。

View File

@@ -0,0 +1,52 @@
# Sa-Sso-Pro 单点登录商业版
### 项目介绍
根据 Sa-Token SSO 模块文档以及官网提供的源码示例您可以很方便的搭建一个SSO模式的认证Demo。
<!-- 然而对于一些企业级项目简单的demo示例显然无法完成我们的项目需求要真正开发一个商业级项目的认证中心系统绝非一朝一夕可以搭建完毕 -->
然而,要真正开发一个商业级项目的认证中心系统,绝非一朝一夕可以搭建完毕,其必不可少的一些功能,
比如:用户账号增删改查维护、登录日志统计、新增用户数据报表、新增 Client 应用接入域名配置……等等,
仍需要我们大量的开发时间。
为此,我们特意准备了项目:[[Sa-Sso-Pro 单点登录商业版]](http://sa-pro.dev33.cn/index.html?hmsr=sa-token)
项目集成了单点登录常见技术点, 绝大多数功能无需二次开发,直接可用,<b style="color: #FF5722;">可大大缩短您的项目接入单点登录的开发周期</b>
### 释疑
##### 1、Sa-Sso-Pro 是收费项目吗?与 Sa-Token 有什么不同?
`Sa-Sso-Pro` 是付费项目,暂不开放源码,如需使用需要购买项目授权,您可以在其主页了解更多详细信息。
`Sa-Sso-Pro``Sa-Token` 的区别,简单来讲:
- `Sa-Token` 是一个框架,需要在项目中通过 pom.xml 引入
- `Sa-Sso-Pro` 是一个完整项目,下载源码后可直接启动
##### 2、Sa-Token 会不会在某一天收费?导致我们项目无法正常运行?
首先我们需要了解一点:**已经发布到 Maven 中央仓库的代码,是不可以删除的**,所以这部分代码是无法做到收费的
其次,像中间件框架,业界没有收费的先例,也没有对应的商业模式,一般的付费项目都是一些成型的完整项目,以解决特定场景的业务需求为目的,
比如:聊天通信、刷脸认证、短信验证码、聚合支付……等等。
Sa-Sso-Pro 并非随意收费,只有当您的系统需要 **统一认证中心** 时您才会用到它,花一笔小钱节省大量开发工期,整体来看,这是非常划算的。
另外:即使您没有购买 `Sa-Sso-Pro`,也不会影响到您对 `Sa-Token` 的使用举个例子MySql具有社区版与企业版即使您没有购买其付费版也不会影响到您对免费 MySql 的使用。
##### 3、Sa-Token 团队日后的主要精力是不是放在 Sa-Sso-Pro 上,降低对 Sa-Token 的支持?毕竟 Sa-Token 是免费的!
答案是不会。
再次强调一下:`Sa-Token``Sa-Sso-Pro` 是两个独立的项目,两者互不影响。
付费项目的出现不会降低对 `Sa-Token` 的支持,`Sa-Token`将会按照原有的发展继续升级迭代。
实际结果可能会恰恰相反:有了盈利来源,`Sa-Token`将发展的更快。
<!-- 衷心感谢每一位粉丝的支持! -->

View File

@@ -0,0 +1,29 @@
# Sa-Token-SSO整合-常见问题总结
---
### 问在模式一与模式二中Client端 必须通过 Alone-Redis 插件来访问Redis吗
答:不必须,只是推荐,权限缓存与业务缓存分离后会减少 `SSO-Redis` 的访问压力,且可以避免多个 `Client端` 的缓存读写冲突
### 问:将旧有系统改造为单点登录时,应该注意哪些?
建议不要把其中一个系统改造为SSO服务端而是新起一个项目作为Server端所有旧有项目全部作为Client端与此对接
### 问SSO模式二第一个域名登录成功之后其他两个不会自动登录
系统1登录成功之后系统二与系统三需要点击登录按钮才会登录成功
> 第一个系统,需要:点击 [登录] 按钮 -> 跳转到登录页 -> 输账号密码 -> 登录成功 <br>
> 第二个系统,需要:点击 [登录] 按钮 -> 登录成功 <br>
> 第三个系统,需要:点击 [登录] 按钮 -> 登录成功 (免去重复跳转登录页输入账号密码的步骤)
### 追问:那我是否可以设计成不需要点登录按钮的,只要访问页面,它就能登录成功
可以:加个过滤器检测到未登录 自动跳转就行了,详细可以参照章节:[[何时引导用户去登录]](/sso/sso-custom-login) 给出的建议进行设计
### 问我参照文档的SSO模式二搭建一直提示Ticket无效请问怎么回事
根据群友的反馈,出现此异常概率最大的原因是因为 `Client``Server` 没有连接同一个RedisSSO模式二中两者必须连接同一个 Redis 才可以登录成功,
如果您排查之后不是此原因可以加入QQ群或者在issues反馈一下
### 还有其它问题?
可以加群反馈一下,比较典型的问题我们解决之后都会提交到此页面方便大家快速排查

View File

@@ -138,7 +138,7 @@ spring:
# Redis服务器连接密码默认为空
password:
```
注意点:`allow-url`为了方便测试配置为`*`线上生产环境一定要配置为详细URL地址 详见下方“配置域名校验”
注意点:`allow-url`为了方便测试配置为`*`线上生产环境一定要配置为详细URL地址 之后的章节我们会详细阐述此配置项
##### 2.4、创建SSO-Server端启动类
``` java
@@ -313,53 +313,12 @@ public class SaSsoClientApplication {
默认测试密码:`sa / 123456`,其余流程保持不变
### 6、配置域名校验
##### 6.1、Ticket劫持攻击
在以上的SSO-Server端示例中配置项 `sa-token.sso.allow-url=*` 意为配置所有允许的Client端授权地址不在此配置项中的URL将无法单点登录成功
以上示例为了方便测试被配置为*,但是,<font color="#FF0000" >在生产环境中,此配置项绝对不能配置为 * </font>否则会有被ticket劫持的风险
假设攻击者根据模仿我们的授权地址巧妙的构造一个URL
> [http://sa-sso-server.com:9000/sso/auth?redirect=https://www.baidu.com/](http://sa-sso-server.com:9000/sso/auth?redirect=https://www.baidu.com/)
当不知情的小红被诱导访问了这个URL时它将被重定向至百度首页
![sso-ticket-jc](https://oss.dev33.cn/sa-token/doc/sso/sso-ticket-jc.png 's-w-sh')
可以看到代表着用户身份的ticket码也显现到了URL之中借此漏洞攻击者完全可以构建一个URL将小红的ticket码自动提交到攻击者自己的服务器伪造小红身份登录网站
##### 6.2、防范方法
造成此漏洞的直接原因就是SSO-Server认证中心没有对 `redirect地址` 进行任何的限制,防范的方法也很简单,就是对`redirect参数`进行校验如果其不在指定的URL列表中时拒绝下放ticket
我们将其配置为一个具体的URL`allow-url=http://sa-sso-client1.com:9001/sso/login`,再次访问上述连接:
![sso-feifa-rf](https://oss.dev33.cn/sa-token/doc/sso/sso-feifa-rf.png 's-w-sh')
域名没有通过校验,拒绝授权!
##### 6.3、配置安全性参考表
| 配置方式 | 举例 | 安全性 | 建议 |
| :-------- | :-------- | :-------- | :-------- |
| 配置为* | `*` | <font color="#F00" >低</font> | **<font color="#F00" >禁止在生产环境下使用</font>** |
| 配置到域名 | `http://sa-sso-client1.com/*` | <font color="#F70" >中</font> | <font color="#F70" >不建议在生产环境下使用</font> |
| 配置到详细地址| `http://sa-sso-client1.com:9001/sso/login` | <font color="#080" >高</font> | <font color="#080" >可以在生产环境下使用</font> |
##### 6.4、疑问为什么不直接回传Token而是先回传ticket再用ticket去查询对应的账号id
Token作为长时间有效的会话凭证在任何时候都不应该直接在暴露URL之中虽然Token直接的暴露本身不会造成安全漏洞但会为很多漏洞提供可乘之机
因此Sa-Token-SSO选择先回传ticket再由ticket获取账号id且ticket一次性用完即废提高安全性
### 7、跨Redis的单点登录
### 6、跨Redis的单点登录
以上流程解决了跨域模式下的单点登录但是后端仍然采用了共享Redis来同步会话如果我们的架构设计中Client端与Server端无法共享Redis又该怎么完成单点登录
这就要采用模式三了,且往下看:[Http请求获取会话](/sso/sso-type3)
这就要采用模式三了,且往下看:[SSO模式三Http请求获取会话](/sso/sso-type3)
<!--