单点登录sso实现方案(单点登录sso企业级解决方案)(1)

阅读收获

✔️1. 了解单点登录实现原理

✔️2. 掌握快速使用xxl-sso接入单点登录功能

一、早期的多系统登录解决方案

二、什么是单点登录

三、为什么需要单点登录

四、单点登录原理

4.1 登录

sso需要一个独立的认证中心,只有认证中心能接受用户的用户名密码等安全信息,其他系统不提供登录入口,只接受认证中心的间接授权。

间接授权通过令牌实现,sso认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,可以借此创建局部会话,局部会话登录方式与单系统的登录方式相同。

这个过程,也就是单点登录的原理,用下图说明

单点登录sso实现方案(单点登录sso企业级解决方案)(2)

  1. 用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
  2. sso认证中心发现用户未登录,将用户引导至登录页面(带系统1地址)
  3. 用户输入用户名密码提交登录申请
  4. sso认证中心校验用户信息,创建用户与sso认证中心之间的会话,称为全局会话,同时创建授权令牌
  5. sso认证中心带着令牌跳转到最初的请求地址(系统1)
  6. 系统1拿到令牌,去sso认证中心校验令牌是否有效
  7. sso认证中心校验令牌,返回有效,注册系统1
  8. 系统1使用该令牌创建与用户的会话,称为局部会话,返回受保护资源
  9. 用户访问系统2的受保护资源
  10. 系统2发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
  11. sso认证中心发现用户已登录,跳转回系统2的地址,并附上令牌
  12. 系统2拿到令牌,去sso认证中心校验令牌是否有效
  13. sso认证中心校验令牌,返回有效,注册系统2
  14. 系统2使用该令牌创建与用户的局部会话,返回受保护资源

用户登录成功之后,会与sso认证中心及访问的子系统建立会话,用户与sso认证中心建立的会话称为全局会话,用户与各个子系统建立的会话称为局部会话,局部会话建立之后,用户访问子系统受保护资源将不再通过sso认证中心,全局会话与局部会话有如下约束关系

  1. 局部会话存在,全局会话一定存在
  2. 全局会话存在,局部会话不一定存在
  3. 全局会话销毁,局部会话必须销毁

4.2 注销

在一个子系统中注销,所有子系统的会话都将被销毁,用下面的图来说明

单点登录sso实现方案(单点登录sso企业级解决方案)(3)

sso认证中心一直监听全局会话的状态,一旦全局会话销毁,监听器将通知所有注册系统执行注销操作

下面对上图简要说明

  1. 用户向系统1发起注销请求
  2. 系统1根据用户与系统1建立的会话id拿到令牌,向sso认证中心发起注销请求
  3. sso认证中心校验令牌有效,销毁全局会话,同时取出所有用此令牌注册的系统地址
  4. sso认证中心向所有注册系统发起注销请求
  5. 各注册系统接收sso认证中心的注销请求,销毁局部会话
  6. sso认证中心引导用户至登录页面

五、快速接入SSO

5.1 xxl-sso特性

5.2 环境

5.3 下载xxl-sso源码

源码仓库地址

Release Download

github.com/xuxueli/xxl…

Download

gitee.com/xuxueli0323…

Download

5.4 文档地址

5.5 项目结构说明

- xxl-sso-server:中央认证服务,支持集群
- xxl-sso-core:Client端依赖
- xxl-sso-samples:单点登陆Client端接入示例项目
    - xxl-sso-web-sample-springboot:基于Cookie接入方式,供用户浏览器访问,springboot版本
    - xxl-sso-token-sample-springboot:基于Token接入方式,常用于无法使用Cookie的场景使用,如APP、Cookie被禁用等,springboot版本
复制代码

5.6 基于Token方式部署

5.6.1 认证中心(SSO Server)搭建

### redis 地址: 如 "{ip}"、"{ip}:{port}"、"{redis/rediss}://xxl-sso:{password}@{ip}:{port:6379}/{db}";多地址逗号分隔
xxl.sso.redis.address=redis://127.0.0.1:6379
### 登录态有效期窗口,默认24H,当登录态有效期窗口过半时,自动顺延一个周期
xxl.sso.redis.expire.minute=1440
复制代码

5.6.2 单点登陆Client端搭建

<dependency>
    <groupId>com.xuxueli</groupId>
    <artifactId>xxl-sso-core</artifactId>
    <version>${最新稳定版}</version>
</dependency>
复制代码
##### SSO Server认证中心地址(推荐以域名方式配置认证中心)
xxl.sso.server=http://xxlssoserver.com:8080/xxl-sso-server

##### 注销登陆path,值为Client端应用的相对路径
xxl.sso.logout.path=/logout

##### 路径排除Path,允许设置多个,且支持Ant表达式。用于排除SSO客户端不需要过滤的路径
xxl-sso.excluded.paths=

### redis   // redis address, like "{ip}"、"{ip}:{port}"、"{redis/rediss}://xxl-sso:{password}@{ip}:{port:6379}/{db}";Multiple "," separated
xxl.sso.redis.address=redis://xxl-sso:password@127.0.0.1:6379/0
xxl.sso.redis.address=redis://127.0.0.1:6379
复制代码
package com.xxl.sso.sample.config;

import com.xxl.sso.core.conf.Conf;
import com.xxl.sso.core.filter.XxlSsoTokenFilter;
import com.xxl.sso.core.util.JedisUtil;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author xuxueli 2018-11-15
 */
@Configuration
public class XxlSsoConfig implements DisposableBean {


    @Value("${xxl.sso.server}")
    private String xxlSsoServer;

    @Value("${xxl.sso.logout.path}")
    private String xxlSsoLogoutPath;

    @Value("${xxl.sso.redis.address}")
    private String xxlSsoRedisAddress;

    @Value("${xxl-sso.excluded.paths}")
    private String xxlSsoExcludedPaths;


    @Bean
    public FilterRegistrationBean xxlSsoFilterRegistration() {

        // xxl-sso, redis init
        JedisUtil.init(xxlSsoRedisAddress);

        // xxl-sso, filter init
        FilterRegistrationBean registration = new FilterRegistrationBean();

        registration.setName("XxlSsoWebFilter");
        registration.setOrder(1);
        registration.addUrlPatterns("/*");
        //token使用的是XxlSsoTokenFilter
        registration.setFilter(new XxlSsoTokenFilter());
        registration.addInitParameter(Conf.SSO_SERVER, xxlSsoServer);
        registration.addInitParameter(Conf.SSO_LOGOUT_PATH, xxlSsoLogoutPath);
        registration.addInitParameter(Conf.SSO_EXCLUDED_PATHS, xxlSsoExcludedPaths);

        return registration;
    }

    @Override
    public void destroy() throws Exception {

        // xxl-sso, redis close
        JedisUtil.close();
    }

}
复制代码

5.6.3 验证 (模拟请求 Token 方式接入SSO的接口)

### 在host文件中添加以下内容0
127.0.0.1 xxlssoserver.com
127.0.0.1 xxlssoclient1.com
127.0.0.1 xxlssoclient2.com
复制代码
##client1
POST http://xxlssoclient1.com:8082/xxl-sso-token-sample-springboot/
Content-Type: application/x-www-form-urlencoded
xxl_sso_sessionid: 1000_bac4555c627e4233b6da7d3f9b91aff5

###

##client2
http://xxlssoclient2.com:8082/xxl-sso-token-sample-springboot/
Content-Type: application/x-www-form-urlencoded
xxl_sso_sessionid: 1000_bac4555c627e4233b6da7d3f9b91aff5



###

##校验
POST http://xxlssoserver.com:8080/xxl-sso-server/app/logincheck
Content-Type: application/x-www-form-urlencoded

sessionId=1000_9df8ee645d7f435fb5f76c9223dfe6e8


###

##注销
POST http://xxlssoserver.com:8080/xxl-sso-server/app/logout
Content-Type: application/x-www-form-urlencoded

sessionId=1000_0ec8e28158da4241926314e0b3b9b834


###

#登录sso
POST http://xxlssoserver.com:8080/xxl-sso-server/app/login
Content-Type: application/x-www-form-urlencoded

username=user&password=123456

复制代码

六、总体设计

6.1 架构图

单点登录sso实现方案(单点登录sso企业级解决方案)(4)

6.2 功能定位

XXL-SSO 是一个分布式单点登录框架。只需要登录一次就可以访问所有相互信任的应用系统。

借助 XXL-SSO,可以快速实现分布式系统单点登录。

6.3 核心概念

概念

说明

SSO Server

中央认证服务,支持集群

SSO Client

接入SSO认证中心的Client应用

SSO SessionId

登录用户会话ID,SSO 登录成功为用户自动分配

SSO User

登录用户信息,与 SSO SessionId 相对应

6.4 登录流程剖析

6.5 注销流程剖析

6.6 基于Cookie,相关概念

6.7 基于Token,相关概念

6.8 未登录状态请求处理

基于Cookie,未登录状态请求:

基于Token,未登录状态请求:

6.9 登录态自动延期

支持自定义登录态有效期窗口,默认24H,当登录态有效期窗口过半时,自动顺延一个周期。

6.10 记住密码

未记住密码时,关闭浏览器则登录态失效;记住密码时,登录态自动延期,在自定义延期时间的基础上,原则上可以无限延期。

6.11 路径排除

自定义路径排除Path,允许设置多个,且支持Ant表达式。用于排除SSO客户端不需要过滤的路径。