单点登录到底是什么?

单点登录到底是什么?

CookieJWT ,从 SessionOAuth2

一篇 图解 + 实战完整入门手册


目录

  1. 导语:为什么要有 SSO
  2. 核心概念
  3. SSO 分类与对比
  4. Cookie-Based SSO 详解
  5. Token-Based SSO 详解
  6. OAuth2 + OpenID Connect 流程
  7. JWT 实战(Spring Boot + Redis)
  8. 常见安全问题 & 防护
  9. 总结:一张图看懂 SSO

导语:为什么要有 SSO?

没有 SSO 的场景:

  • 公司 5 个系统 → 用户记 5 套账号 → IT 部门天天重置密码
  • 员工离职 → 5 个系统分别禁用账号 → 漏一个 = 安全风险

单点登录(SSO)一次登录,全网通行一次退出,全网失效


核心概念

概念 说明
CAS Central Authentication Service(中央认证服务)
Token 登录后颁发的 凭证(JWT、Ticket)
TGT Ticket Granting Ticket(CAS 术语)
ST Service Ticket(CAS 术语)
IdP Identity Provider(身份提供者)
SP Service Provider(服务提供者)

SSO 分类与对比

类型 存储 代表协议 适用场景
Cookie-Based 浏览器 Cookie CAS 2.0/3.0 同域名
Token-Based Header/LocalStorage JWT/OIDC 跨域、前后端分离
OAuth2 Access Token OAuth2 + OIDC 第三方登录

1. 架构图(同域名)

2. 关键点

  • Cookie Domain.example.com → 二级域名共享
  • Token 验证 :各系统向 SSO 中心 校验(Redis/JWT)
  • 退出:SSO 中心清除 Cookie + 各系统清除本地 Session

Token-Based SSO 详解

1. 跨域场景(前后端分离)

sequenceDiagram participant U as 浏览器 participant F as 前端A participant B as 后端A participant S as SSO中心 participant F2 as 前端B participant B2 as 后端B F->>S: POST /api/login {user,pwd} S->>F: 200 {token: jwt} F->>B: GET /api/user Header: Authorization: Bearer jwt B->>B: 验证 JWT → 成功 F2->>S: GET /api/user Header: Authorization: Bearer jwt S->>F2: 200 {userInfo}

2. JWT 结构

css 复制代码
Header.Base64.Payload.Base64.Signature
  • Header{"alg":"HS256","typ":"JWT"}
  • Payload{"sub":"alice","exp":1719999999}
  • SignatureHMACSHA256(header + "." + payload, secret)

OAuth2 + OpenID Connect 流程

1. 授权码模式(最常用)

sequenceDiagram participant U as 用户 participant C as 客户端 participant G as Google(IDP) participant R as Resource Server U->>C: 点击"用 Google 登录" C->>G: 302 → authorize?client_id=xxx&response_type=code&scope=openid U->>G: 登录并同意授权 G->>C: 302 → redirect_uri?code=AUTH_CODE C->>G: POST /token {code, client_secret} G->>C: 200 {access_token, id_token(JWT)} C->>R: GET /userinfo Header: Bearer access_token R->>C: 200 {sub: "alice", name: "Alice"}

JWT 实战(Spring Boot + Redis)

1. 项目结构

css 复制代码
src
 ├─ config/JwtConfig.java
 ├─ controller/LoginController.java
 ├─ filter/JwtFilter.java
 └─ SpringBootSsoApplication.java

2. 生成 JWT

java 复制代码
@Component
public class JwtProvider {

    private final String secret = "demoSecretKey";
    private final long validity = 3600_000; // 1h

    public String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + validity))
                .signWith(SignatureAlgorithm.HS256, secret)
                .compact();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
            return true;
        } catch (JwtException e) {
            return false;
        }
    }
}

3. 过滤器验证

java 复制代码
@Component
public class JwtFilter extends OncePerRequestFilter {

    @Autowired
    private JwtProvider provider;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        String header = request.getHeader("Authorization");
        if (header != null && header.startsWith("Bearer ")) {
            String token = header.substring(7);
            if (provider.validateToken(token)) {
                String username = Jwts.parser()
                                      .setSigningKey(provider.secret)
                                      .parseClaimsJws(token)
                                      .getBody()
                                      .getSubject();
                SecurityContextHolder.getContext().setAuthentication(
                        new UsernamePasswordAuthenticationToken(username, null, Collections.emptyList()));
            }
        }
        filterChain.doFilter(request, response);
    }
}

4. 登录接口

java 复制代码
@RestController
public class LoginController {

    @Autowired
    private JwtProvider provider;

    @PostMapping("/login")
    public Map<String, Object> login(@RequestBody LoginRequest req) {
        // 省略密码校验
        String token = provider.generateToken(req.getUsername());
        return Map.of("token", token);
    }
}

常见安全问题 & 防护

攻击 防护
Token 泄露 HTTPS + 短有效期
XSS 窃取 HttpOnly Cookie
CSRF SameSite=Strict + CSRF Token
重放攻击 JWT 过期时间 + Redis 黑名单

总结:一张图看懂 SSO

graph TD A[浏览器] -->|登录| B[SSO中心] B -->|颁发 Token| A A -->|携带 Token| C[系统A] A -->|携带 Token| D[系统B] C -->|验证 Token| B D -->|验证 Token| B

口诀一次登录,全网通行;一次退出,全网失效;Token 短,HTTPS 长。

相关推荐
程序员黑豆5 小时前
Java 注释详解:单行、多行与文档注释的完整指南
java·前端·ai编程
hey_sml6 小时前
JAVA每日一学---CompletableFuture中thenApply与thenCompose区别详解
java·开发语言
Doraemomo6 小时前
数据结构-环形链表
java·数据结构·链表
维克兜率天7 小时前
【维克】ARMA模型:AR与MA的完美结合
后端·restful
萧瑟余晖7 小时前
Java深入解析篇十七之SpringCloud
java·开发语言
是未才8 小时前
从输入 URL 到页面返回:DNS、路由、TLS 与 HTTP 完整链路
java·后端·计算机网络
上海安当技术8 小时前
半天接入:USBKey RESTful API + C 动态库,Web 和 C/S 两套集成路径实战
前端·后端·restful·集成·usbkey
ttod_qzstudio8 小时前
Java 常用语法极简通关(五):类与对象——字段、方法、构造器、this 与 static
java·开发语言·python
DevUI团队9 小时前
从“即兴创作”到“规格先行”,华为云码道(CodeArts)代码智能体持续深耕企业级规范驱动开发能力
前端·人工智能·后端
萧瑟余晖9 小时前
Java深入解析篇十七之Spring Security
java·开发语言·spring