单点登录到底是什么?

单点登录到底是什么?

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 长。

相关推荐
MXM_777几秒前
laravel 并发控制写法-涉及资金
java·数据库·oracle
这就是佬们吗7 分钟前
告别 Node.js 版本冲突:NVM 安装与使用全攻略
java·linux·前端·windows·node.js·mac·web
何中应7 分钟前
@Autowrited和@Resource注解的区别及使用场景
java·开发语言·spring boot·后端·spring
源代码•宸8 分钟前
Golang语法进阶(Context)
开发语言·后端·算法·golang·context·withvalue·withcancel
christine-rr8 分钟前
linux常用命令(9)——查看系统与硬件信息
linux·运维·服务器·网络·后端
一条咸鱼_SaltyFish8 分钟前
[Day16] Bug 排查记录:若依框架二次开发中的经验与教训 contract-security-ruoyi
java·开发语言·经验分享·微服务·架构·bug·开源软件
源代码•宸9 分钟前
Golang语法进阶(Sync、Select)
开发语言·经验分享·后端·算法·golang·select·pool
荒诞硬汉10 分钟前
递归的学习
java·学习
孤独天狼11 分钟前
java设计模式
java
IT_陈寒11 分钟前
2024年JavaScript开发者必备的10个ES13新特性实战指南
前端·人工智能·后端