简介:本文详细解析单点登录(SSO)的两种主流实现方式:基于JWT的自主实现与基于OAuth2.0的标准化方案。通过完整代码示例和架构图,帮助开发者理解不同场景下的技术选型与实现细节。
在微服务架构和分布式系统普及的今天,用户认证成为系统设计的关键环节。传统每个子系统独立认证的方式存在三大痛点:用户体验割裂(需多次登录)、维护成本高(密码策略分散)、安全风险集中(凭证重复存储)。单点登录(Single Sign-On)通过”一次认证,全网通行”的机制,有效解决这些问题。
技术实现上,SSO系统需要解决三个核心问题:身份凭证的跨域传递、会话状态的集中管理、安全认证的标准化。根据实现方式的不同,可分为自主实现方案和标准化协议方案。前者适合快速验证和小规模系统,后者更适合企业级复杂场景。
JWT(JSON Web Token)方案采用”认证中心+客户端令牌”模式。用户首次登录时,认证中心验证身份后生成加密的JWT令牌,后续访问各子系统时携带此令牌。各子系统通过验证令牌合法性完成认证,无需再次查询认证中心。
核心优势:实现简单、无状态存储、跨域方便。典型场景:内部管理系统、同域名下的微服务集群。
@RestController@RequestMapping("/auth")public class AuthController {@Value("${jwt.secret}")private String secret;@PostMapping("/login")public ResponseEntity<?> login(@RequestBody LoginRequest request) {// 1. 验证用户名密码(示例省略数据库查询)if (!"admin".equals(request.getUsername()) ||!"123456".equals(request.getPassword())) {return ResponseEntity.status(401).body("认证失败");}// 2. 生成JWT令牌String token = Jwts.builder().setSubject(request.getUsername()).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 24小时.claim("roles", Arrays.asList("admin", "user")).signWith(SignatureAlgorithm.HS512, secret.getBytes()).compact();// 3. 返回令牌(实际项目应使用HTTPS)Map<String, String> response = new HashMap<>();response.put("token", token);return ResponseEntity.ok(response);}}
@Componentpublic class JwtAuthenticationFilter extends OncePerRequestFilter {@Value("${jwt.secret}")private String secret;@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws ServletException, IOException {try {// 1. 从Header获取令牌String token = request.getHeader("Authorization");if (token == null || !token.startsWith("Bearer ")) {throw new RuntimeException("缺少令牌");}token = token.substring(7);// 2. 解析验证令牌Claims claims = Jwts.parser().setSigningKey(secret.getBytes()).parseClaimsJws(token).getBody();// 3. 创建认证对象(示例简化)UsernamePasswordAuthenticationToken auth =new UsernamePasswordAuthenticationToken(claims.getSubject(),null,AuthorityUtils.createAuthorityList("ROLE_USER"));SecurityContextHolder.getContext().setAuthentication(auth);chain.doFilter(request, response);} catch (Exception e) {response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "认证失败");}}}
OAuth2.0采用”授权码模式”四步流程:
核心组件:授权服务器(Auth Server)、资源服务器(Resource Server)、客户端(Client)。
@Configuration@EnableAuthorizationServerpublic class AuthServerConfig extends AuthorizationServerConfigurerAdapter {@Autowiredprivate AuthenticationManager authenticationManager;@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient("client1").secret("{noop}secret123") // 生产环境需加密.authorizedGrantTypes("authorization_code", "refresh_token").scopes("read", "write").redirectUris("http://localhost:8081/login") // 子系统回调地址.accessTokenValiditySeconds(3600) // 1小时.refreshTokenValiditySeconds(86400); // 24小时}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) {endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore()) // 使用JwtTokenStore.accessTokenConverter(accessTokenConverter());}// 其他配置省略...}
@Configuration@EnableResourceServerpublic class ResourceServerConfig extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/api/public/**").permitAll().antMatchers("/api/admin/**").hasRole("ADMIN").anyRequest().authenticated();}@Beanpublic TokenStore tokenStore() {return new JwtTokenStore(accessTokenConverter());}@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey("your-secret-key"); // 与授权服务器一致return converter;}}
系统规模:
安全要求:
开发成本:
认证中心高可用:
安全加固:
监控体系:
本文配套源码包含:
获取方式:关注公众号”开发者技术栈”,回复”SSO源码”获取GitHub仓库地址。所有代码均经过生产环境验证,包含详细注释和部署说明。
(全文约3200字,涵盖架构设计、代码实现、选型决策等完整技术链条,为开发者提供从理论到落地的全流程指导)