单点登录(SSO)实战:基于Vue与Spring Boot的深度实现

发布于:2025-04-02 ⋅ 阅读:(18) ⋅ 点赞:(0)

一、SSO的本质价值与实现模型

在分布式系统架构中,单点登录(Single Sign-On)如同企业级应用的"万能钥匙",用户只需在统一认证中心完成一次身份验证,即可访问所有互信系统。其核心在于建立可信的令牌传递机制,我们选择JWT(JSON Web Token)作为载体,结合OAuth2简化模式实现轻量级SSO方案。

关键技术原理:

  1. 认证中心统一鉴权:独立部署的认证服务负责用户身份核验

  2. 令牌传播机制:使用数字签名的JWT保障令牌安全传输

  3. 跨域会话管理:通过Cookie+LocalStorage实现跨域状态同步

(图源网络,侵权删除)

二、前端Vue实现方案

1. 核心依赖配置

npm install axios vue-router js-cookie

2. 路由守卫实现鉴权

// router/index.js
router.beforeEach((to, from, next) => {
  const token = Cookies.get('SSO_TOKEN');
  
  if (to.meta.requiresAuth) {
    if (!token) {
      // 重定向到认证中心
      window.location.href = `https://auth-center.com/login?redirect=${encodeURIComponent(window.location.href)}`;
    } else {
      // 验证令牌有效性
      axios.get('/api/verify_token', {
        headers: { 'Authorization': `Bearer ${token}` }
      }).then(() => next()).catch(() => {
        Cookies.remove('SSO_TOKEN');
        next('/login');
      });
    }
  } else {
    next();
  }
});

3. 令牌回调处理

​​​​​​​// LoginCallback.vue
export default {
  mounted() {
    const token = this.$route.query.token;
    if (token) {
      Cookies.set('SSO_TOKEN', token, { expires: 1 });
      const redirect = decodeURIComponent(this.$route.query.redirect || '/');
      this.$router.push(redirect);
    }
  }
}

三、后端Java实现(Spring Boot)

1. Maven依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. JWT工具类

public class JwtUtil {
    private static final String SECRET_KEY = "your-256-bit-secret";
    private static final long EXPIRATION = 3600L * 1000; // 1小时

    public static String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
                .signWith(Keys.hmacShaKeyFor(SECRET_KEY.getBytes()))
                .compact();
    }

    public static Claims parseToken(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(SECRET_KEY.getBytes())
                .build()
                .parseClaimsJws(token)
                .getBody();
    }
}

3. 认证中心接口

@RestController
@RequestMapping("/auth")
public class AuthController {

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest request) {
        // 1. 执行用户名密码验证
        User user = userService.authenticate(request);
        
        // 2. 生成JWT令牌
        String token = JwtUtil.generateToken(user.getUsername());
        
        // 3. 返回带跳转地址的响应
        return ResponseEntity.ok(Map.of(
            "token", token,
            "redirect", request.getRedirectUrl()
        ));
    }
}

4. 业务系统鉴权拦截器

public class JwtInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        if (StringUtils.isEmpty(token)) {
            throw new AuthException("Missing authentication token");
        }
        
        try {
            Claims claims = JwtUtil.parseToken(token.replace("Bearer ", ""));
            request.setAttribute("username", claims.getSubject());
            return true;
        } catch (JwtException e) {
            throw new AuthException("Invalid token");
        }
    }
}

四、安全增强策略

  1. HTTPS强制传输:全链路启用SSL加密

  2. 双Token机制:AccessToken(短时效) + RefreshToken(长时效)

  3. 跨域安全配置

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("https://your-domain.com")
                .allowCredentials(true)
                .allowedMethods("GET", "POST");
    }
}

五、典型问题排查指南

现象 排查方向 解决方案
跨域请求失败 CORS配置、Cookie作用域 检查Origin头、SameSite设置
Token无法解析 密钥一致性、编码格式 验证HS256算法和Base64编码
会话状态不同步 域名协议一致性、存储方式 确保二级域名相同,检查LocalStorage