一、SSO的本质价值与实现模型
在分布式系统架构中,单点登录(Single Sign-On)如同企业级应用的"万能钥匙",用户只需在统一认证中心完成一次身份验证,即可访问所有互信系统。其核心在于建立可信的令牌传递机制,我们选择JWT(JSON Web Token)作为载体,结合OAuth2简化模式实现轻量级SSO方案。
关键技术原理:
-
认证中心统一鉴权:独立部署的认证服务负责用户身份核验
-
令牌传播机制:使用数字签名的JWT保障令牌安全传输
-
跨域会话管理:通过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 {@Overridepublic 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");}}
}
四、安全增强策略
-
HTTPS强制传输:全链路启用SSL加密
-
双Token机制:AccessToken(短时效) + RefreshToken(长时效)
-
跨域安全配置:
@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("https://your-domain.com").allowCredentials(true).allowedMethods("GET", "POST");}
}
五、典型问题排查指南
现象 | 排查方向 | 解决方案 |
---|---|---|
跨域请求失败 | CORS配置、Cookie作用域 | 检查Origin头、SameSite设置 |
Token无法解析 | 密钥一致性、编码格式 | 验证HS256算法和Base64编码 |
会话状态不同步 | 域名协议一致性、存储方式 | 确保二级域名相同,检查LocalStorage |