> 演示Demo站点 http://sso.exrick.cn
# 前后端分离下单点登录实现
| 单点登录模式 | 优点 |缺点 |
| --- | --- | --- |
|共享Cookie模式 | 简单方便,用户体验好 |根域名需限制一致;Cookie可能不安全|
|OAuth2.0模式 |灵活安全,不受站点限制 |成本稍高,需独立的认证中心 |
|跨域设置Cookie |用户体验好,不受站点限制 |比较麻烦;Cookie可能不安全 |
|客户端模式 |用户体验好,不受站点限制 |成本极高,依赖于用户本地安装客户端应用 |
## 共享Cookie模式[【完整版】](http://xpay.exrick.cn/pay?xboot)
- 首先需进入“系统管理-系统配置”菜单中的“其他配置”设置你应用部署的一级域名,用户登录后将在该域名及子级域名下存储Cookie令牌`accessToken`用于其他站点获取接口,完整版用户详见`xboot-sso`项目。
- 其他站点从Cookie中取出`accessToken`即`Cookies.get("accessToken")`即可携带上`accessToken`请求其他接口,通常用于内部信任的站点
<img src="https://ooo.0o0.ooo/2019/08/19/yrgX4fdOhUSincs.png" width="600px">
## OAuth2.0模式
### 认证中心
- 即通过平台的独立统一认证站点完成身份认证,其他站点通过获取access_token完成授权以及之后的请求鉴权
- XBoot统一认证地址: 运行前端,路由地址为`/authorize`,默认即 http://127.0.0.1:9999/authorize, 在线demo地址 http://xboot.exrick.cn/authorize
### 单点登录流程分析示例
> 两三句话就能讲明白的事情,网上的大多资料画再复杂的时序图也讲不清关键点
- 站点1发现用户未登录时,跳转至认证中心
- 认证中心发现用户未登录(Cookie中没有认证记录),显示认证中心的登录页面
- 用户输入账号密码登录,认证成功后,**前端记录认证信息保存后端返回的accessToken令牌(可通过令牌获取对应用户名username)**,后端Redis存入access_token对应信息,其key为`username:站点1的clientId`,返回站点1的access_token
- 认证中心携带access_token跳转至站点1的回调地址
- 站点1前端获取到access_token令牌,记录已登录状态,每次请求携带access_token
---
- 站点2发现用户未登录时,跳转至认证中心
- 认证中心前端判断已认证授权过:**从前端Cookie中取出存储的accessToken(可通过令牌获取对应用户名username)**
- 认证中心调用已授权验证接口,先验证accessToken是否有效,若有效,则后端Redis存入新站点的access_token信息,其key为`username:站点2的clientId`,返回站点2的access_token
- 认证中心携带access_token跳转至站点2的回调地址
- 站点2前端获取到access_token令牌,记录已登录状态,每次请求携带access_token
### 注销流程分析示例
- 任一站点用户退出登录,通过Redis失效所有以`username`开头的键值对即可
### 实现细节补充
- 认证中心可通过clientId可获取站点的基本信息数据
### 退出登录接口
- `/xboot/oauth2/logout`
- 需要携带主站的`accessToken`,通常为信任的内部站点中使用,将删除失效当前用户登录的`accessToken`以及当前用户授权第三方应用的`access_token`
### 自动授权说明
- 设置为自动授权后
<img src=https://s1.ax1x.com/2020/05/27/tk71Fs.png width=400/>
- 已认证登录的用户**不会**看到以下授权确认页面,将自动授权跳转。通常用于内部信任的站点以及单点登录的实现
<img src=https://s1.ax1x.com/2020/05/27/tk7IfI.png width=400/>
## 跨域设置Cookie模式
> 淘宝、京东采用的方式
- 完全跨域的情况下`a.com`是肯定不能直接在`b.com`下设置Cookie的,那怎么办?
- **开放设置Cookie接口**。b站点提供一个能在其站点下设置其Cookie的GET接口或JS脚本,供其他信任的站点如a站点调用
- 用户先在a站点登录成功后,通知调用其他站点的接口,为其他站点设置上Cookie,实现单点登录
- 核心技术点:**利用GET请求加载静态资源无跨域限制(无同源限制)**,即JSONP的原理
``` javascript
// a站点中将令牌给b站点
<script type="text/javascript" src="http://b.com/setCookie?accessToken=令牌"/>
// 动态创建
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://b.com/setCookie?accessToken=令牌';
document.head.appendChild(script);
```
- Github上也有一些JSONP的库,如 [https://github.com/webmodules/jsonp](https://github.com/webmodules/jsonp)
~~~shell
$ npm install jsonp --save
~~~
~~~js
const jsonp = require('jsonp');
jsonp('http://b.com/setCookie?accessToken=令牌', null, (err, data) => {
if (err) {
console.error(err.message);
} else {
console.log(data);
}
});
~~~
- 退出登录同理,调用退出登录接口后端清除会话后,获得要清空的其他站点列表,依次调用清除前端Cookie
- 当然这中间还涉及很多安全校验,此处不再赘述
## 客户端单点登录模式
> QQ客户端单点登录流程分析
- 当本机电脑上启动了QQ客户端,再使用浏览器访问QQ相关站点,如QQ邮箱,会显示我们已经登录了的QQ账号信息提供快速登录
<img src=https://s1.ax1x.com/2020/05/27/tEIL7Q.png width=300/>
- 其关键原理为QQ客户端**内置一了个小型的 Web Server监听了4301端口**,并提供当前登录QQ信息的接口
- 访问QQ邮箱登录页后会生成校验参数去访问这 Web Server提供的接口,实际地址为`https://localhost.ptlogin2.qq.com:4301/`,这个域名指向的是 127.0.0.1,可以解决Cookie跨域等权限问题
```js
请求
GET https://localhost.ptlogin2.qq.com:4301/pt_get_uins?callback=ptui_getuins_CB&r=0.5658049977525998&pt_local_tk=-440325439
响应
var var_sso_uin_list=[{"uin":1012139570,"face_index":-1,"gender":0,"nickname":"Exrick","client_type":66818,"uin_flag":8388612,"account":1012139570}];ptui_getuins_CB(var_sso_uin_list);
```
- 由于QQ有庞大的用户基群并且能保证大部分人安装使用QQ客户端,因此通过该方式为用户提供了便利
- 前言&版本说明
- 概念
- XBoot 是什么?
- 系统架构
- 主要使用的开源组件
- 角色控制访问权限(RBAC)
- 用户手册
- 系统配置
- 工作流使用配置
- 定时任务调度
- 智能助手客服机器人
- 项目本地运行
- 后端运行
- 前端运行
- 项目结构说明
- 附:使用Oracle等数据库
- 模块化版本
- 后端开发指南
- 基本开发指南
- 前后端数据交互标准
- 工具类及数据权限
- 代码生成器-30秒搞定CRUD
- 增删改查CRUD
- 日志类型注解扩展
- 逻辑删除
- 各验证码使用及配置
- 接口文档使用及认证
- 前端开发指南
- 基本开发指南
- 主题/Logo/首页等配置
- 路由菜单配置
- 多语言国际化配置
- 自定义图标icon
- 工具类及数据获取
- 其他说明
- 完整版开发指南
- 前端Vue代码生成器
- Activiti工作流
- 单点登录配置
- 智能助手/客服机器人
- MinIO对象存储服务搭建
- 第三方社交账号配置
- 短信开发/站内消息/邮件
- Vaptcha验证码
- 禁用词使用
- 前端移除CDN
- 其他说明
- 开放平台及单点登录
- 开放平台使用指南
- Web接入开发流程
- 单点登录开发指南
- 微信小程序端开发指南
- 项目导入与开发必读
- 业务组件
- 产品组件(小)
- 产品组件(大)
- 优惠券组件
- 评论列表组件
- 红包组件
- 推荐商品组件
- 页面设计
- 商品详情页及SKU设计
- 通用方法工具类说明
- 开发经验与踩坑分享
- Uniapp端开发指南
- APP后端开发指南
- Uniapp前端开发指南
- 开发新功能示例
- 后端开发新模块
- 前端开发新页面
- 测试
- SonarQube代码质量管理
- TestNG单元测试
- ExtentReports测试报告
- Selenuim自动化Web测试
- Appuim自动化App测试
- JMeter压测性能测试
- 部署
- Spring Boot配置
- 快速部署
- 后端部署
- 前端部署
- 前端部署优化
- Docker容器化部署
- 服务器配置
- 持续集成
- GitLab
- GitLab CI
- XBoot 脚本参考
- Jenkins
- Jenkins安装
- XBoot CI参考
- DevOps环境搭建
- 组件安装列表
- 开发设计规范
- 分支管理
- 数据库设计规范
- Redis使用规范
- Java基础开发规范
- Rest API规范
- 项目结构规范
- 前端开发规范
- 前端设计规范
- 项目搭建分享
- 后端相关
- SpringBoot 2.x区别总结
- Spring Security整合JWT
- Spring Security动态权限管理
- Spring Boot 2.x整合Quartz
- Spring Boot 2.x整合Websocket
- Spring Boot 2.x整合Activiti工作流以及模型设计器
- Spring Boot + Security全局跨域配置
- 前端相关
- axios请求封装 统一异常处理
- 动态路由菜单加载
- 多维度控制权限至按钮显示
- 发送消息图标红点实时显示
- 动态组件单页操作
- XBoot助你【告别996】
- 业务开发踩坑
- 你会用开发神器IDEA吗
- Lombok你知道多少
- 你还在手动校验参数吗
- 你真的会用JPA吗
- Lamda表达式
- Stream流式API
- 告别资源关闭
- Optional避免null
- 谷歌Guava工具包
- 线程池
- 其他小经验技巧
- 更新日志及步骤
- 常见问题