Skip to content
广告❤️成为赞助商

什么是单点登录

单点登录的英文名叫做:Single Sign On(简称SSO)。

  • 用人话说:就是在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统。

会话状态及存储

会话状态:客户端和服务端之间通信过程产生的状态信息。

在开始做单点登录之前,咱们需要理解有无状态会话机制及存储机制,值得注意的是有无状态没有绝对的好坏, 需要根据实际情况来设计,当然也可以是结合使用。

会话存储:用于存储登录明文或密文信息。

名称只读说明
Local Storage允许在浏览器中存储 key/value 对的数据, 用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。
Session Storage允许在浏览器中存储 key/value 对的数据, 用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据。
Cookie服务端、客户端都可以创建,存储在浏览器 Cookies 中,分为会话 cookie (浏览器关闭失效) 和持久化 cookie (到期失效)。
Session服务端创建,储存在服务端,可以存储大量的数据(默认生命周期为30分钟),以会话 cookie 存储 sessionId 状态通信

有状态会话

普通登录逻辑

  • 1,用户登录
  • 2,服务端设置 session
  • 3,设置会话 cookie 存储 sessionId
  • 4,用户访问系统资源
  • 5,根据会话 sessionId 找到 web 容器中的 session 登录信息

sso1

单点登录逻辑

  • 1,用户登录 Nginx 负载均衡路由
  • 2,登录某个节点
  • 3,web 容器存储会话 session 至分布式缓存 Redis
  • 4,用户访问系统资源
  • 5,Nginx 路由至其它节点
  • 6,web 容器从分布式缓存 Redis 中读取 session 登录信息

sso11

无状态会话

无状态利用的是加密技术,换人话就是 token 登录票据中存储了登录关键信息,后端解密直接得到登录信息。

  • 1,用户登录
  • 2,Nginx 路由至任意节点
  • 3,生成加密 token 票据
  • 4,存储在浏览器端,可以是 cookie 也可以是 Local Storage 中存储
  • 5,用户访问系统资源,需要携带登录 token 票据
  • 6,任意节点 sso 客户端会解密 token 票据获取登录信息

sso2

注意

  1. 浏览器安全策略限制,不同ip、不同端口、不同域名 都属于跨域。
  2. 请必须理解会话存储 LocalStorage、SessionStorage、Cookie、Session 的区别和作用。
  3. 请必须理解有无状态会话的区别,去思考如何应用到自己系统中。

kisso

kisso

kisso = cookie sso 它是一把快速开发 java Web 登录系统(SSO)的瑞士军刀。

Kisso 采用 jwt 生成 token 票据,轻薄封装设计上摒弃客户端服务端模式一体式设计。 只需要引用一个依赖即可一行代码完成单点登录逻辑。

安装依赖

https://search.maven.org/search?q=g:com.baomidou

  • Apache Maven
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>kisso</artifactId>
  <version>3.8.1</version>
</dependency>
  • Gradle DSL
implementation("com.baomidou:kisso:3.8.1")

测试 demo

使用文档

// 生成 jwt 票据,访问请求头设置‘ accessToken=票据内容 ’ 适合前后分离模式单点登录
String jwtToken = SSOToken.create().setId(1).setIssuer("admin").setOrigin(TokenOrigin.HTML5).getToken();

// 解析票据
SSOToken ssoToken = SSOToken.parser(jwtToken);

// Cookie 模式设置
SSOHelper.setCookie(request, response,  new SSOToken().setId(String.valueOf(1)).setIssuer("admin"));

// 登录权限拦截器类 SSOSpringInterceptor
// 注解不拦截 @LoginIgnore
// yml 配置 kisso.config....
  • Spring Boot
@ControllerAdvice
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // SSO 授权拦截器
        SSOSpringInterceptor ssoInterceptor = new SSOSpringInterceptor();
        ssoInterceptor.setHandlerInterceptor(new LoginHandlerInterceptor());
        registry.addInterceptor(ssoInterceptor).addPathPatterns("/**").excludePathPatterns("/v1/sso/**");
    }
}

默认 HS512 算法

// HS512 密钥,配置参数 kisso.config.sign-key
SSOHelper.getHS512SecretKey()

切换 RS512 算法

  • 1,配置算法 kisso.config.sign-algorithm = RS512
  • 2,配置私钥公钥证书,默认放置 resources 目录即可
// RSA 密钥,配置参数 kisso.config.rsa-jks-store
// 其它参数 CN=Server,OU=Unit,O=Organization,L=City,S=State,C=US
// RSA 生成 jks 密钥
$ keytool -genkeypair -alias jwtkey -keyalg RSA -dname "CN=llt" -keypass keypassword -keystore key.jks -storepass jkspassword

// RSA 生成证书
// RSA 公钥,配置参数 kisso.config.rsa-cert-store
$ keytool -export -alias jwtkey -file public.cert -keystore key.jks -storepass jkspassword

常见安全策略

  • Secure 标记为 Secure 的 Cookie 只应通过被HTTPS协议加密过的请求发送给服务端。使用 HTTPS 安全协议,可以保护 Cookie 在浏览器和 Web 服务器间的传输过程中不被窃取和篡改。

  • HTTPOnly 设置 HTTPOnly 属性可以防止客户端脚本通过 document.cookie 等方式访问 Cookie,有助于避免 XSS 攻击。

  • SameSite SameSite 属性可以让 Cookie 在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击(CSRF)。

SameSite 可以有下面三种值:
1、Strict仅允许一方请求携带 Cookie,即浏览器将只发送相同站点请求的 Cookie,即当前网页 URL 与请求目标 URL 完全一致。
2、Lax允许部分第三方请求携带 Cookie
3、None无论是否跨站都会发送 Cookie
造成现在无法获取cookie是因为之前默认是 None 的,Chrome80 后默认是 Lax
  • 安全配置如下:
kisso:
  config:
    # 开启 https 有效,传输更安全
    cookie-secure: true
    # 防止 XSS 防止脚本攻击
    cookie-http-only: true
    # 防止 CSRF 跨站攻击
    cookie-same-site: Lax
    # 加密算法 RSA
    sign-algorithm: RS512
    ...
  • 配置 config 属性说明
名称默认说明
encodingUTF-8编码格式
signKey签名密钥(用于对称算法)
signAlgorithmHS512签名算法
rsaJksStorekey.jksRSA 私钥存储路径(开启 RSA 算法有效)
rsaCertStorepublic.certRSA 公钥存储路径(开启 RSA 算法有效)
rsaAliasjwtkeyRSA 密钥 Alias(开启 RSA 算法有效)
rsaKeypassllTs1p68KRSA 密钥 keypass(开启 RSA 算法有效)
rsaStorepassllTs1p68KRSA 密钥 storepass(开启 RSA 算法有效)
accessTokenNameaccessToken访问票据名(访问票据在 Header 中默认名称)
cookieNameuidcookie 名称(无状态 cookie 模式有效)
cookieDomaincookie 所在有效域名,不设置为当前访问域名(无状态 cookie 模式有效)
cookiePath/cookie 路径(无状态 cookie 模式有效)
cookieSecure/cookie 路径(无状态 cookie 模式有效)
cookieSecurefalsecookie 是否设置安全,设置 true 那么只能为 https 协议访问(无状态 cookie 模式有效)
cookieHttpOnlytruecookie 是否为只读状态,设置 js 无法获取、预防脚本攻击(无状态 cookie 模式有效)
cookieMaxAge-1cookie 有效期 -1 关闭浏览器失效(无状态 cookie 模式有效)
cookieSameSitecookie的SameSite属性用来限制第三方Cookie,从而减少安全风险(防止CSRF) 支持三种模式:Strict 仅允许一方请求携带Cookie,即浏览器将只发送相同站点请求的Cookie,即当前网页URL与请求目标URL完全一致,浏览器默认该模式。、Lax 允许部分第三方请求携带Cookie、None 无论是否跨站都会发送Cookie(无状态 cookie 模式有效)
cookieBrowserfalse是否验证 token 设置时浏览器信息
cookieCheckIp-1是否验证 token 设置时浏览器信息
loginUrl登录地址(设置后拦截器自动跳转)
logoutUrl退出地址(设置后拦截器自动跳转)
paramReturnUrl参数 ReturnURL登录成功回调地址(设置后拦截器自动跳转)
cacheExpires-1缓存有效期设置
ssoTokennull访问票据
permissionUrifalse权限认证
pluginListnull插件列表
cachenullSSO 缓存
authorizationnullSSO 权限授权

注意

  1. 原则上建议采用 RS512 算法,偷懒者除外。
  2. Cookie 模式也是依赖 Jwt 生成登录票据,不同在于存储在 Cookie 可以利用 Cookie 的浏览器自动携带及子域名跨域实现无状态单独登录。
  3. 跨域是单独登录的拦路虎,必须掌握利用 LocalStorage、SessionStorage、Cookie、Session 解决多应用间的互信。

每个人都是架构师