一、微服务安全概述

微服务架构下,安全是一个核心挑战:

安全威胁:

  • 认证信息泄露
  • Token被伪造
  • 跨站请求攻击(CSRF)
  • 越权访问

二、OAuth2.0协议

1. OAuth2.0授权流程

┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐
│  用户   │     │ 前端   │     │ 认证服务器│     │ 资源服务器│
└────┬────┘     └────┬────┘     └────┬────┘     └────┬────┘
     │               │               │               │
     │ 1.点击登录   │               │               │
     │─────────────>│               │               │
     │               │ 2.跳转授权   │               │
     │<─────────────│               │               │
     │               │ 3.授权       │               │
     │─────────────>│               │               │
     │               │ 4.返回授权码│               │
     │<─────────────│               │               │
     │               │ 5.换Token   │               │
     │               │─────────────>│               │
     │               │<────────────│               │
     │               │ 6.Token    │               │
     │<─────────────│               │               │
     │               │ 7.请求资源   │               │
     │─────────────>│─────────────>│               │
     │               │<────────────│               │
     │<─────────────│               │               │

2. Spring Security + OAuth2.0实现

依赖配置:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

Security配置:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .sessionManagement(session -> 
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**", "/auth/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> jwt.jwtDecoder(jwtDecoder()))
            );
        
        return http.build();
    }
    
    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withJwkSetUri("http://auth-server/oauth2/.well-known/jwks.json")
            .build();
    }
}

三、JWT实战

1. JWT结构

JWT = Header.Payload.Signature

Header: {"alg": "RS256", "typ": "JWT"}
Payload: {"sub": "123", "exp": 1704067200, "roles": ["USER"]}
Signature: RS256(Header.Payload, privateKey)

2. JWT生成

@Service
public class JwtService {
    
    @Value("${jwt.private-key}")
    private String privateKey;
    
    public String generateToken(UserDetails user) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", user.getId());
        claims.put("roles", user.getRoles());
        
        return Jwts.builder()
            .setClaims(claims)
            .setSubject(user.getUsername())
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + 3600000))
            .signWith(getPrivateKey(), SignatureAlgorithm.RS256)
            .compact();
    }
    
    private PrivateKey getPrivateKey() {
        try {
            PKCS8EncodedKeySpec spec = 
                new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
            KeyFactory factory = KeyFactory.getInstance("RSA");
            return factory.generatePrivate(spec);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

3. JWT验证

@Service
public class JwtAuthService {
    
    @Value("${jwt.public-key}")
    private String publicKey;
    
    public Authentication authenticate(String token) {
        try {
            Claims claims = Jwts.parserBuilder()
                .setSigningKey(getPublicKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
            
            String username = claims.getSubject();
            List<GrantedAuthority> authorities = 
                ((List<?>) claims.get("roles")).stream()
                    .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                    .collect(Collectors.toList());
            
            UserDetails userDetails = 
                User.builder().username(username).authorities(authorities).build();
            
            return new UsernamePasswordAuthenticationToken(
                userDetails, null, authorities);
                
        } catch (JwtException e) {
            throw new JwtAuthenticationException("Invalid token");
        }
    }
}

四、Token管理

1. Access Token + Refresh Token

@Service
public class TokenService {
    
    public TokenPair generateTokens(User user) {
        // Access Token: 短期(1小时)
        String accessToken = jwtService.generateAccessToken(user);
        
        // Refresh Token: 长期(7天)
        String refreshToken = jwtService.generateRefreshToken(user);
        
        return new TokenPair(accessToken, refreshToken);
    }
    
    public String refreshAccessToken(String refreshToken) {
        Claims claims = jwtService.validateRefreshToken(refreshToken);
        String userId = claims.getSubject();
        
        User user = userService.getById(Long.parseLong(userId));
        return jwtService.generateAccessToken(user);
    }
}

2. Token黑名单

@Service
public class TokenBlacklistService {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    public void addToBlacklist(String token, long expiration) {
        redisTemplate.opsForValue().set(
            "blacklist:" + token, 
            "1", 
            expiration, 
            TimeUnit.SECONDS
        );
    }
    
    public boolean isBlacklisted(String token) {
        return Boolean.TRUE.equals(
            redisTemplate.hasKey("blacklist:" + token)
        );
    }
}

五、微服务认证

1. 网关统一认证

@Component
public class JwtAuthFilter implements GatewayFilter {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = extractToken(exchange.getRequest());
        
        if (token != null) {
            try {
                Authentication auth = jwtAuthService.authenticate(token);
                ServerWebExchangeUtils.put(exchange, 
                    "AUTHENTICATION", auth);
            } catch (Exception e) {
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
        }
        
        return chain.filter(exchange);
    }
}

2. Feign传递Token

@Configuration
public class FeignConfig {
    
    @Bean
    public RequestInterceptor requestInterceptor() {
        return template -> {
            // 从上下文获取Token
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            if (auth != null && auth.getCredentials() instanceof String) {
                String token = (String) auth.getCredentials();
                template.header("Authorization", "Bearer " + token);
            }
        };
    }
}

六、安全最佳实践

1. HTTPS强制

# application.yml
server:
  ssl:
    enabled: true
    key-store: classpath:keystore.p12
    key-store-password: password
    key-store-type: PKCS12

2. 密码加密

@Service
public class PasswordEncoder {
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}

// 使用BCrypt
@Bean
public PasswordEncoder bcryptEncoder() {
    return new BCryptPasswordEncoder(12);
}

3. 限流防刷

@Component
public class RateLimitFilter implements GatewayFilter {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String ip = getClientIp(exchange.getRequest());
        String key = "ratelimit:" + ip;
        
        Long count = redisTemplate.opsForValue().increment(key);
        if (count != null && count == 1) {
            redisTemplate.expire(key, 60, TimeUnit.SECONDS);
        }
        
        if (count != null && count > 100) {
            exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
            return exchange.getResponse().setComplete();
        }
        
        return chain.filter(exchange);
    }
}

七、总结

微服务安全架构核心要点:

  • OAuth2.0:标准授权协议
  • JWT:无状态Token
  • 网关认证:统一入口
  • Token管理:有效期+黑名单

个人观点,仅供参考

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐