美文网首页Java开发
Single Sign-On(SSO)简介

Single Sign-On(SSO)简介

作者: _浅墨_ | 来源:发表于2025-11-03 19:31 被阅读0次

我们来从 Java开发者视角 深入讲清楚 Single Sign-On(SSO) 的 原理 + 流程图 + 常见实现方案 + 实战代码示例(基于 Spring Boot + JWT + Redis)


🧠 一、什么是 Single Sign-On(SSO)

SSO(单点登录) 是一种身份认证机制,允许用户在多个独立系统之间一次登录、处处通行

✅ 举例说明:

你在访问公司门户(portal.company.com)登录后,
再打开“工单系统(jira.company.com)”或“文档系统(wiki.company.com)”,
不需要再次输入账号密码,这就是 SSO 的效果。


⚙️ 二、SSO 的核心原理

SSO 的关键目标:

让认证中心(Auth Server)统一处理登录逻辑
各个子系统(Client Apps)只负责验证 Token。

📈 典型架构图(简化)

      ┌───────────────────────────────┐
      │        Authentication Server  │
      │        (SSO / OAuth2.0)       │
      │        /login   /token        │
      └──────────┬────────────────────┘
                 │
        ① 用户在 A 系统登录,获得 token
                 │
                 ▼
      ┌────────────────────┐
      │  System A (portal) │───┐
      └────────────────────┘   │
                               │ ② 访问其他系统时,携带 token
                               ▼
      ┌────────────────────┐   │
      │  System B (wiki)   │◄──┘
      └────────────────────┘

🔁 三、SSO 登录流程(逻辑步骤)

步骤 说明
1️⃣ 用户访问受保护的系统(如 wiki.company.com)
2️⃣ 系统发现用户未登录,重定向到 SSO 登录中心
3️⃣ 用户在 SSO 登录中心输入账号密码,登录成功
4️⃣ SSO 生成一个全局 Ticket / Token,并将该凭证返回
5️⃣ 业务系统使用该凭证向 SSO 服务器验证(后端对后端通信)
6️⃣ 验证通过后,业务系统为用户创建本地 Session(或 JWT)
7️⃣ 用户再次访问其他系统时,直接使用同一 Token,无需登录

🔑 四、主流实现方式

实现模式 说明 代表技术
Cookie + Session 同域名子系统共享 Cookie 适合同域(如 a.company.com, b.company.com
Token(JWT) 跨域、移动端友好,服务端无状态 OAuth2 / OpenID Connect
CAS(Central Authentication Service) 学术界早期标准,支持多语言客户端 Jasig CAS Server
OAuth2 / OIDC 标准化协议,支持授权与认证 Spring Authorization Server / Keycloak

💡 五、SSO 实战实现(Spring Boot + JWT + Redis)

场景:我们要实现一个简单的 SSO 登录中心 + 两个业务系统。

🧩 1. 依赖配置(pom.xml)

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.11.5</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

🧠 2. 登录中心 Controller 示例

@RestController
@RequestMapping("/sso")
public class SsoController {

    private final JwtService jwtService;
    private final StringRedisTemplate redisTemplate;

    public SsoController(JwtService jwtService, StringRedisTemplate redisTemplate) {
        this.jwtService = jwtService;
        this.redisTemplate = redisTemplate;
    }

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest request) {
        // 模拟验证账号密码
        if ("admin".equals(request.getUsername()) && "123456".equals(request.getPassword())) {
            String token = jwtService.generateToken(request.getUsername());

            // 将 token 存入 Redis,设置有效期 30 分钟
            redisTemplate.opsForValue().set("SSO:TOKEN:" + token, request.getUsername(), 30, TimeUnit.MINUTES);

            return ResponseEntity.ok(Map.of("token", token));
        }
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");
    }

    @GetMapping("/validate")
    public ResponseEntity<?> validateToken(@RequestParam String token) {
        boolean valid = jwtService.validateToken(token);
        if (!valid) return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        return ResponseEntity.ok(Map.of("username", jwtService.getUsername(token)));
    }
}

🔐 3. JWT 工具类

@Service
public class JwtService {
    private final String SECRET_KEY = "fancylab-secret-key";

    public String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(Date.from(Instant.now().plusSeconds(1800)))
                .signWith(Keys.hmacShaKeyFor(SECRET_KEY.getBytes()), SignatureAlgorithm.HS256)
                .compact();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder().setSigningKey(SECRET_KEY.getBytes()).build().parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public String getUsername(String token) {
        return Jwts.parserBuilder().setSigningKey(SECRET_KEY.getBytes())
                .build().parseClaimsJws(token).getBody().getSubject();
    }
}

🏗️ 4. 业务系统验证 Token 逻辑

@Component
public class TokenInterceptor implements HandlerInterceptor {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private JwtService jwtService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        String token = request.getHeader("Authorization");
        if (token == null || !jwtService.validateToken(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        // 检查Redis
        String username = redisTemplate.opsForValue().get("SSO:TOKEN:" + token);
        if (username == null) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        request.setAttribute("username", username);
        return true;
    }
}

注册拦截器:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired private TokenInterceptor tokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/login", "/public/**");
    }
}

🔄 六、Token 与 Cookie 对比总结

特性 Cookie/Session Token (JWT)
存储位置 服务端 客户端
跨域支持 较差 较好
状态 有状态 无状态
适用场景 同域 Web 系统 微服务 / 移动端 / 前后端分离
性能 需要 session 同步 验证轻量、可分布式

🚀 七、进阶方向

  1. 🔑 集成 OAuth2.1 + OIDC(Spring Authorization Server / Keycloak)
  2. 🧱 实现 统一登出(Single Logout):Redis 删除 token
  3. 🔄 Token 刷新机制(Refresh Token)
  4. 🧩 接入前端(Vue/iOS)实现跨系统登录态共享

🎯 八、总结一句话

SSO 本质就是让“身份认证”从每个系统中抽离出来,统一由独立的认证中心负责。

你可以通过 JWT + Redis + Spring Security / Authorization Server
快速实现一个安全、可扩展的企业级单点登录体系。

相关文章

  • Single-Sign-On核心原理解析

    关键词:SSO Single Sign On 单点登录 Single sign-on (SSO) is a pro...

  • 在onelogin中使用OpenId Connect Authe

    简介 onelogin是一个优秀的SSO(Single Sign-On)服务提供商,我们可以借助onelogin的...

  • SSO单点登录原理

    ### 什么是SSO? - 单点登录( Single Sign-On , 简称 SSO )是目前比较流行的服务于企...

  • SSO

    SSO 是什么 ? SSO(Single Sign-on),即单点登录,指在一个多系统共存的环境下,用户在一处登录...

  • 单点登录(SSO)简介

    单点登录SSO(Single Sign-On)是身份管理中的一部分。SSO的一种较为通俗的定义是:SSO是指访问同...

  • 单点登录SSO

    一、什么是单点登录SSO(Single Sign-On)SSO是一种统一认证和授权机制,指访问同一服务器不同应用中...

  • 单点登录

    一、什么是单点登录SSO(Single Sign-On)SSO是一种统一认证和授权机制,指访问同一服务器不同应用中...

  • cas单点登录与springboot关联使用

    1.cas单点登录介绍 单点登录( Single Sign-On , 简称 SSO )是目前比较流行的服务于企业业...

  • 单点登录简单原理及实现

    1 定义 单点登录(英语:Single sign-on,缩写为 SSO),一种对于许多相互关连,但是又是各自独立的...

  • Salesforce中的单点登录简介

    单点登录的定义 引自维基百科: 单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一...

网友评论

    本文标题:Single Sign-On(SSO)简介

    本文链接:https://www.haomeiwen.com/subject/vtfzxstx.html