在微服务架构中,接口鉴权和限流是保障系统安全性和稳定性的重要机制。本文将深入剖析这些机制背后的核心数据结构和算法,揭示其设计原理和实现细节。

微服务安全架构概览

安全挑战

微服务架构带来了新的安全挑战:

  1. 服务间通信安全:多个服务之间需要安全的通信机制
  2. 身份认证和授权:统一的身份认证和细粒度的权限控制
  3. API网关安全:作为入口的网关需要强大的安全防护
  4. 流量控制:防止恶意攻击和系统过载
  5. 监控和审计:全链路的安全监控和日志审计

核心安全组件

  1. 身份认证服务:JWT、OAuth2、OIDC
  2. 授权服务:RBAC、ABAC权限模型
  3. API网关:统一入口、路由、限流
  4. 限流组件:令牌桶、漏桶、滑动窗口
  5. 监控组件:实时监控、异常检测

身份认证机制

1. JWT(JSON Web Token)实现

JWT是一种无状态的身份认证机制,通过数字签名保证令牌的完整性。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
public class JWTManager {
    private final String secretKey;
    private final long tokenValidityInSeconds;
    private final Algorithm algorithm;

    public JWTManager(String secretKey, long tokenValidityInSeconds) {
        this.secretKey = secretKey;
        this.tokenValidityInSeconds = tokenValidityInSeconds;
        this.algorithm = Algorithm.HMAC256(secretKey);
    }

    // JWT头部信息
    public static class JWTHeader {
        private String alg = "HS256";
        private String typ = "JWT";

        // getter和setter方法
        public String getAlg() { return alg; }
        public String getTyp() { return typ; }
    }

    // JWT载荷信息
    public static class JWTPayload {
        private String sub;          // 主题(用户ID)
        private String iss;          // 签发者
        private String aud;          // 受众
        private long exp;            // 过期时间
        private long iat;            // 签发时间
        private long nbf;            // 生效时间
        private String jti;          // JWT ID
        private Map<String, Object> claims; // 自定义声明

        public JWTPayload() {
            this.claims = new HashMap<>();
            this.iat = System.currentTimeMillis() / 1000;
            this.nbf = this.iat;
        }

        // getter和setter方法
        public String getSub() { return sub; }
        public void setSub(String sub) { this.sub = sub; }

        public long getExp() { return exp; }
        public void setExp(long exp) { this.exp = exp; }

        public Map<String, Object> getClaims() { return claims; }
        public void addClaim(String key, Object value) { this.claims.put(key, value); }
    }

    // 生成JWT令牌
    public String generateToken(String userId, Map<String, Object> claims) {
        try {
            JWTPayload payload = new JWTPayload();
            payload.setSub(userId);
            payload.setExp(System.currentTimeMillis() / 1000 + tokenValidityInSeconds);

            // 添加自定义声明
            if (claims != null) {
                claims.forEach(payload::addClaim);
            }

            return JWT.create()
                    .withSubject(payload.getSub())
                    .withExpiresAt(new Date(payload.getExp() * 1000))
                    .withIssuedAt(new Date(payload.iat * 1000))
                    .withClaim("roles", (String) claims.get("roles"))
                    .withClaim("permissions", (List<String>) claims.get("permissions"))
                    .sign(algorithm);

        } catch (Exception e) {
            throw new RuntimeException("JWT token generation failed", e);
        }
    }

    // 验证JWT令牌
    public JWTPayload validateToken(String token) {
        try {
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT decodedJWT = verifier.verify(token);

            JWTPayload payload = new JWTPayload();
            payload.setSub(decodedJWT.getSubject());
            payload.setExp(decodedJWT.getExpiresAt().getTime() / 1000);

            // 提取自定义声明
            Claim rolesClaim = decodedJWT.getClaim("roles");
            if (!rolesClaim.isNull()) {
                payload.addClaim("roles", rolesClaim.asString());
            }

            Claim permissionsClaim = decodedJWT.getClaim("permissions");
            if (!permissionsClaim.isNull()) {
                payload.addClaim("permissions", permissionsClaim.asList(String.class));
            }

            return payload;

        } catch (JWTVerificationException e) {
            throw new RuntimeException("JWT token validation failed", e);
        }
    }

    // 刷新令牌
    public String refreshToken(String token) {
        JWTPayload payload = validateToken(token);

        // 检查令牌是否即将过期(提前5分钟刷新)
        long currentTime = System.currentTimeMillis() / 1000;
        if (payload.getExp() - currentTime > 300) {
            return token; // 不需要刷新
        }

        // 生成新令牌
        return generateToken(payload.getSub(), payload.getClaims());
    }

    // 解析令牌(不验证签名)
    public JWTPayload parseToken(String token) {
        try {
            DecodedJWT decodedJWT = JWT.decode(token);

            JWTPayload payload = new JWTPayload();
            payload.setSub(decodedJWT.getSubject());
            payload.setExp(decodedJWT.getExpiresAt().getTime() / 1000);

            return payload;
        } catch (JWTDecodeException e) {
            throw new RuntimeException("JWT token parsing failed", e);
        }
    }
}

// JWT认证拦截器
@Component
public class JWTAuthenticationInterceptor implements HandlerInterceptor {
    private final JWTManager jwtManager;
    private final RedisTemplate<String, String> redisTemplate;

    public JWTAuthenticationInterceptor(JWTManager jwtManager,
                                       RedisTemplate<String, String> redisTemplate) {
        this.jwtManager = jwtManager;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler) throws Exception {
        String token = extractToken(request);

        if (token == null) {
            sendUnauthorizedResponse(response, "Missing authentication token");
            return false;
        }

        try {
            // 检查令牌是否在黑名单中
            if (isTokenBlacklisted(token)) {
                sendUnauthorizedResponse(response, "Token has been revoked");
                return false;
            }

            // 验证令牌
            JWTManager.JWTPayload payload = jwtManager.validateToken(token);

            // 将用户信息存储到请求上下文
            request.setAttribute("userId", payload.getSub());
            request.setAttribute("userClaims", payload.getClaims());

            return true;

        } catch (RuntimeException e) {
            sendUnauthorizedResponse(response, "Invalid authentication token");
            return false;
        }
    }

    private String extractToken(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }

    private boolean isTokenBlacklisted(String token) {
        String key = "blacklist:" + DigestUtils.sha256Hex(token);
        return redisTemplate.hasKey(key);
    }

    private void sendUnauthorizedResponse(HttpServletResponse response, String message)
            throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json");
        response.getWriter().write("{\"error\":\"" + message + "\"}");
    }
}

2. OAuth2授权码流程实现

OAuth2是一个开放的授权标准,支持多种授权流程。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
// OAuth2授权服务器
@RestController
@RequestMapping("/oauth2")
public class OAuth2AuthorizationServer {
    private final AuthorizationCodeService authCodeService;
    private final AccessTokenService accessTokenService;
    private final ClientService clientService;

    // 授权码存储
    @Service
    public static class AuthorizationCodeService {
        private final RedisTemplate<String, String> redisTemplate;
        private final Random random = new SecureRandom();

        public AuthorizationCodeService(RedisTemplate<String, String> redisTemplate) {
            this.redisTemplate = redisTemplate;
        }

        // 生成授权码
        public String generateAuthCode(String clientId, String userId, String redirectUri,
                                     String scope) {
            String code = generateRandomCode();

            AuthCodeInfo authCodeInfo = new AuthCodeInfo();
            authCodeInfo.setClientId(clientId);
            authCodeInfo.setUserId(userId);
            authCodeInfo.setRedirectUri(redirectUri);
            authCodeInfo.setScope(scope);
            authCodeInfo.setExpiresAt(System.currentTimeMillis() + 600_000); // 10分钟

            String key = "auth_code:" + code;
            String value = JsonUtils.toJson(authCodeInfo);

            redisTemplate.opsForValue().set(key, value, Duration.ofMinutes(10));

            return code;
        }

        // 验证并消费授权码
        public AuthCodeInfo validateAndConsumeAuthCode(String code, String clientId,
                                                      String redirectUri) {
            String key = "auth_code:" + code;
            String value = redisTemplate.opsForValue().get(key);

            if (value == null) {
                throw new RuntimeException("Invalid or expired authorization code");
            }

            AuthCodeInfo authCodeInfo = JsonUtils.fromJson(value, AuthCodeInfo.class);

            // 验证客户端ID和重定向URI
            if (!authCodeInfo.getClientId().equals(clientId) ||
                !authCodeInfo.getRedirectUri().equals(redirectUri)) {
                throw new RuntimeException("Invalid client or redirect URI");
            }

            // 检查是否过期
            if (System.currentTimeMillis() > authCodeInfo.getExpiresAt()) {
                throw new RuntimeException("Authorization code expired");
            }

            // 删除授权码(一次性使用)
            redisTemplate.delete(key);

            return authCodeInfo;
        }

        private String generateRandomCode() {
            byte[] bytes = new byte[32];
            random.nextBytes(bytes);
            return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
        }
    }

    // 访问令牌服务
    @Service
    public static class AccessTokenService {
        private final JWTManager jwtManager;
        private final RedisTemplate<String, String> redisTemplate;

        public AccessTokenService(JWTManager jwtManager,
                                RedisTemplate<String, String> redisTemplate) {
            this.jwtManager = jwtManager;
            this.redisTemplate = redisTemplate;
        }

        // 生成访问令牌
        public TokenResponse generateTokens(String userId, String clientId, String scope) {
            Map<String, Object> claims = new HashMap<>();
            claims.put("client_id", clientId);
            claims.put("scope", scope);

            String accessToken = jwtManager.generateToken(userId, claims);
            String refreshToken = generateRefreshToken();

            // 存储刷新令牌
            RefreshTokenInfo refreshTokenInfo = new RefreshTokenInfo();
            refreshTokenInfo.setUserId(userId);
            refreshTokenInfo.setClientId(clientId);
            refreshTokenInfo.setScope(scope);
            refreshTokenInfo.setExpiresAt(System.currentTimeMillis() + 2592000000L); // 30天

            String key = "refresh_token:" + refreshToken;
            String value = JsonUtils.toJson(refreshTokenInfo);
            redisTemplate.opsForValue().set(key, value, Duration.ofDays(30));

            TokenResponse response = new TokenResponse();
            response.setAccessToken(accessToken);
            response.setRefreshToken(refreshToken);
            response.setTokenType("Bearer");
            response.setExpiresIn(3600); // 1小时
            response.setScope(scope);

            return response;
        }

        // 使用刷新令牌生成新的访问令牌
        public TokenResponse refreshAccessToken(String refreshToken) {
            String key = "refresh_token:" + refreshToken;
            String value = redisTemplate.opsForValue().get(key);

            if (value == null) {
                throw new RuntimeException("Invalid refresh token");
            }

            RefreshTokenInfo refreshTokenInfo = JsonUtils.fromJson(value, RefreshTokenInfo.class);

            if (System.currentTimeMillis() > refreshTokenInfo.getExpiresAt()) {
                redisTemplate.delete(key);
                throw new RuntimeException("Refresh token expired");
            }

            return generateTokens(refreshTokenInfo.getUserId(),
                                refreshTokenInfo.getClientId(),
                                refreshTokenInfo.getScope());
        }

        private String generateRefreshToken() {
            return UUID.randomUUID().toString().replace("-", "");
        }
    }

    // 授权端点
    @GetMapping("/authorize")
    public ResponseEntity<String> authorize(@RequestParam String clientId,
                                          @RequestParam String redirectUri,
                                          @RequestParam String responseType,
                                          @RequestParam(required = false) String scope,
                                          @RequestParam(required = false) String state,
                                          HttpServletRequest request) {
        try {
            // 验证客户端
            ClientInfo client = clientService.getClientById(clientId);
            if (client == null || !client.getRedirectUris().contains(redirectUri)) {
                return ResponseEntity.badRequest().body("Invalid client or redirect URI");
            }

            // 检查用户是否已登录
            String userId = (String) request.getAttribute("userId");
            if (userId == null) {
                // 重定向到登录页面
                String loginUrl = "/login?redirect=" +
                    URLEncoder.encode(request.getRequestURL().toString() + "?" +
                    request.getQueryString(), StandardCharsets.UTF_8);
                return ResponseEntity.status(302).header("Location", loginUrl).build();
            }

            // 生成授权码
            String authCode = authCodeService.generateAuthCode(clientId, userId, redirectUri, scope);

            // 构建重定向URL
            StringBuilder redirectUrl = new StringBuilder(redirectUri);
            redirectUrl.append("?code=").append(authCode);
            if (state != null) {
                redirectUrl.append("&state=").append(state);
            }

            return ResponseEntity.status(302).header("Location", redirectUrl.toString()).build();

        } catch (Exception e) {
            return ResponseEntity.badRequest().body("Authorization failed: " + e.getMessage());
        }
    }

    // 令牌端点
    @PostMapping("/token")
    public ResponseEntity<TokenResponse> token(@RequestParam String grantType,
                                             @RequestParam(required = false) String code,
                                             @RequestParam(required = false) String redirectUri,
                                             @RequestParam(required = false) String refreshToken,
                                             @RequestParam String clientId,
                                             @RequestParam String clientSecret) {
        try {
            // 验证客户端凭证
            if (!clientService.validateClient(clientId, clientSecret)) {
                return ResponseEntity.status(401).build();
            }

            TokenResponse response;
            switch (grantType) {
                case "authorization_code":
                    response = handleAuthorizationCodeGrant(code, clientId, redirectUri);
                    break;
                case "refresh_token":
                    response = handleRefreshTokenGrant(refreshToken);
                    break;
                default:
                    return ResponseEntity.badRequest().build();
            }

            return ResponseEntity.ok(response);

        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }

    private TokenResponse handleAuthorizationCodeGrant(String code, String clientId,
                                                     String redirectUri) {
        AuthCodeInfo authCodeInfo = authCodeService.validateAndConsumeAuthCode(code, clientId, redirectUri);
        return accessTokenService.generateTokens(authCodeInfo.getUserId(), clientId, authCodeInfo.getScope());
    }

    private TokenResponse handleRefreshTokenGrant(String refreshToken) {
        return accessTokenService.refreshAccessToken(refreshToken);
    }
}

// 数据类定义
class AuthCodeInfo {
    private String clientId;
    private String userId;
    private String redirectUri;
    private String scope;
    private long expiresAt;

    // getter和setter方法
    public String getClientId() { return clientId; }
    public void setClientId(String clientId) { this.clientId = clientId; }

    public String getUserId() { return userId; }
    public void setUserId(String userId) { this.userId = userId; }

    public String getRedirectUri() { return redirectUri; }
    public void setRedirectUri(String redirectUri) { this.redirectUri = redirectUri; }

    public String getScope() { return scope; }
    public void setScope(String scope) { this.scope = scope; }

    public long getExpiresAt() { return expiresAt; }
    public void setExpiresAt(long expiresAt) { this.expiresAt = expiresAt; }
}

class RefreshTokenInfo {
    private String userId;
    private String clientId;
    private String scope;
    private long expiresAt;

    // getter和setter方法省略...
}

class TokenResponse {
    private String accessToken;
    private String refreshToken;
    private String tokenType;
    private int expiresIn;
    private String scope;

    // getter和setter方法省略...
}

class ClientInfo {
    private String clientId;
    private String clientSecret;
    private Set<String> redirectUris;
    private Set<String> grantTypes;

    // getter和setter方法省略...
}

权限控制模型

1. RBAC(基于角色的访问控制)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
// RBAC权限管理系统
public class RBACPermissionManager {
    private final Map<String, User> users;
    private final Map<String, Role> roles;
    private final Map<String, Permission> permissions;
    private final Map<String, Set<String>> userRoles;
    private final Map<String, Set<String>> rolePermissions;

    public RBACPermissionManager() {
        this.users = new ConcurrentHashMap<>();
        this.roles = new ConcurrentHashMap<>();
        this.permissions = new ConcurrentHashMap<>();
        this.userRoles = new ConcurrentHashMap<>();
        this.rolePermissions = new ConcurrentHashMap<>();
    }

    // 用户实体
    public static class User {
        private String userId;
        private String username;
        private String email;
        private boolean enabled;

        public User(String userId, String username, String email) {
            this.userId = userId;
            this.username = username;
            this.email = email;
            this.enabled = true;
        }

        // getter和setter方法
        public String getUserId() { return userId; }
        public String getUsername() { return username; }
        public boolean isEnabled() { return enabled; }
    }

    // 角色实体
    public static class Role {
        private String roleId;
        private String roleName;
        private String description;
        private boolean enabled;

        public Role(String roleId, String roleName, String description) {
            this.roleId = roleId;
            this.roleName = roleName;
            this.description = description;
            this.enabled = true;
        }

        // getter和setter方法
        public String getRoleId() { return roleId; }
        public String getRoleName() { return roleName; }
        public boolean isEnabled() { return enabled; }
    }

    // 权限实体
    public static class Permission {
        private String permissionId;
        private String resource;
        private String action;
        private String description;

        public Permission(String permissionId, String resource, String action, String description) {
            this.permissionId = permissionId;
            this.resource = resource;
            this.action = action;
            this.description = description;
        }

        // getter和setter方法
        public String getPermissionId() { return permissionId; }
        public String getResource() { return resource; }
        public String getAction() { return action; }
    }

    // 添加用户
    public void addUser(User user) {
        users.put(user.getUserId(), user);
        userRoles.putIfAbsent(user.getUserId(), ConcurrentHashMap.newKeySet());
    }

    // 添加角色
    public void addRole(Role role) {
        roles.put(role.getRoleId(), role);
        rolePermissions.putIfAbsent(role.getRoleId(), ConcurrentHashMap.newKeySet());
    }

    // 添加权限
    public void addPermission(Permission permission) {
        permissions.put(permission.getPermissionId(), permission);
    }

    // 分配角色给用户
    public void assignRoleToUser(String userId, String roleId) {
        if (users.containsKey(userId) && roles.containsKey(roleId)) {
            userRoles.get(userId).add(roleId);
        }
    }

    // 分配权限给角色
    public void assignPermissionToRole(String roleId, String permissionId) {
        if (roles.containsKey(roleId) && permissions.containsKey(permissionId)) {
            rolePermissions.get(roleId).add(permissionId);
        }
    }

    // 检查用户权限
    public boolean hasPermission(String userId, String resource, String action) {
        User user = users.get(userId);
        if (user == null || !user.isEnabled()) {
            return false;
        }

        Set<String> userRoleSet = userRoles.get(userId);
        if (userRoleSet == null) {
            return false;
        }

        // 遍历用户的所有角色
        for (String roleId : userRoleSet) {
            Role role = roles.get(roleId);
            if (role == null || !role.isEnabled()) {
                continue;
            }

            Set<String> rolePermissionSet = rolePermissions.get(roleId);
            if (rolePermissionSet == null) {
                continue;
            }

            // 检查角色的权限
            for (String permissionId : rolePermissionSet) {
                Permission permission = permissions.get(permissionId);
                if (permission != null &&
                    permission.getResource().equals(resource) &&
                    permission.getAction().equals(action)) {
                    return true;
                }
            }
        }

        return false;
    }

    // 获取用户所有权限
    public Set<Permission> getUserPermissions(String userId) {
        Set<Permission> userPermissions = new HashSet<>();
        Set<String> userRoleSet = userRoles.get(userId);

        if (userRoleSet != null) {
            for (String roleId : userRoleSet) {
                Set<String> rolePermissionSet = rolePermissions.get(roleId);
                if (rolePermissionSet != null) {
                    for (String permissionId : rolePermissionSet) {
                        Permission permission = permissions.get(permissionId);
                        if (permission != null) {
                            userPermissions.add(permission);
                        }
                    }
                }
            }
        }

        return userPermissions;
    }

    // 权限缓存装饰器
    public static class CachedRBACPermissionManager {
        private final RBACPermissionManager rbacManager;
        private final Cache<String, Boolean> permissionCache;
        private final Cache<String, Set<Permission>> userPermissionCache;

        public CachedRBACPermissionManager(RBACPermissionManager rbacManager) {
            this.rbacManager = rbacManager;
            this.permissionCache = Caffeine.newBuilder()
                    .maximumSize(10000)
                    .expireAfterWrite(Duration.ofMinutes(15))
                    .build();
            this.userPermissionCache = Caffeine.newBuilder()
                    .maximumSize(1000)
                    .expireAfterWrite(Duration.ofMinutes(30))
                    .build();
        }

        public boolean hasPermission(String userId, String resource, String action) {
            String cacheKey = userId + ":" + resource + ":" + action;
            return permissionCache.get(cacheKey, k -> rbacManager.hasPermission(userId, resource, action));
        }

        public Set<Permission> getUserPermissions(String userId) {
            return userPermissionCache.get(userId, rbacManager::getUserPermissions);
        }

        // 清除用户权限缓存
        public void invalidateUserCache(String userId) {
            userPermissionCache.invalidate(userId);
            // 清除相关的权限检查缓存
            permissionCache.asMap().keySet().removeIf(key -> key.startsWith(userId + ":"));
        }
    }
}

// 权限注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequirePermission {
    String resource();
    String action();
}

// 权限切面
@Aspect
@Component
public class PermissionAspect {
    private final RBACPermissionManager.CachedRBACPermissionManager permissionManager;

    public PermissionAspect(RBACPermissionManager.CachedRBACPermissionManager permissionManager) {
        this.permissionManager = permissionManager;
    }

    @Around("@annotation(requirePermission)")
    public Object checkPermission(ProceedingJoinPoint joinPoint, RequirePermission requirePermission) throws Throwable {
        // 从请求上下文获取用户ID
        String userId = getCurrentUserId();

        if (userId == null) {
            throw new SecurityException("User not authenticated");
        }

        boolean hasPermission = permissionManager.hasPermission(
                userId,
                requirePermission.resource(),
                requirePermission.action()
        );

        if (!hasPermission) {
            throw new SecurityException("Access denied: insufficient permissions");
        }

        return joinPoint.proceed();
    }

    private String getCurrentUserId() {
        // 从SecurityContext或RequestAttributes获取当前用户ID
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes != null) {
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            return (String) request.getAttribute("userId");
        }
        return null;
    }
}

限流算法实现

1. 令牌桶算法

令牌桶算法通过控制令牌的生成速率来限制请求频率。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
public class TokenBucketRateLimiter {
    private final long capacity;          // 桶容量
    private final long refillRate;        // 令牌补充速率(每秒)
    private volatile long tokens;         // 当前令牌数
    private volatile long lastRefillTime; // 上次补充时间
    private final Object lock = new Object();

    public TokenBucketRateLimiter(long capacity, long refillRate) {
        this.capacity = capacity;
        this.refillRate = refillRate;
        this.tokens = capacity;
        this.lastRefillTime = System.nanoTime();
    }

    // 尝试获取指定数量的令牌
    public boolean tryAcquire(long tokensRequested) {
        if (tokensRequested <= 0) {
            return true;
        }

        synchronized (lock) {
            refillTokens();

            if (tokens >= tokensRequested) {
                tokens -= tokensRequested;
                return true;
            }

            return false;
        }
    }

    // 尝试获取单个令牌
    public boolean tryAcquire() {
        return tryAcquire(1);
    }

    // 补充令牌
    private void refillTokens() {
        long currentTime = System.nanoTime();
        long timePassed = currentTime - lastRefillTime;

        if (timePassed > 0) {
            long tokensToAdd = (timePassed * refillRate) / 1_000_000_000L;
            tokens = Math.min(capacity, tokens + tokensToAdd);
            lastRefillTime = currentTime;
        }
    }

    // 获取当前令牌数
    public long getAvailableTokens() {
        synchronized (lock) {
            refillTokens();
            return tokens;
        }
    }

    // 分布式令牌桶实现
    public static class DistributedTokenBucketRateLimiter {
        private final RedisTemplate<String, String> redisTemplate;
        private final String bucketKey;
        private final long capacity;
        private final long refillRate;

        // Lua脚本,确保原子性操作
        private static final String LUA_SCRIPT = """
            local key = KEYS[1]
            local capacity = tonumber(ARGV[1])
            local refillRate = tonumber(ARGV[2])
            local tokensRequested = tonumber(ARGV[3])
            local currentTime = tonumber(ARGV[4])

            local bucket = redis.call('hmget', key, 'tokens', 'lastRefillTime')
            local tokens = tonumber(bucket[1]) or capacity
            local lastRefillTime = tonumber(bucket[2]) or currentTime

            -- 计算需要补充的令牌数
            local timePassed = math.max(0, currentTime - lastRefillTime)
            local tokensToAdd = math.floor(timePassed * refillRate / 1000)
            tokens = math.min(capacity, tokens + tokensToAdd)

            -- 检查是否有足够的令牌
            if tokens >= tokensRequested then
                tokens = tokens - tokensRequested
                redis.call('hmset', key, 'tokens', tokens, 'lastRefillTime', currentTime)
                redis.call('expire', key, 3600)
                return 1
            else
                redis.call('hmset', key, 'tokens', tokens, 'lastRefillTime', currentTime)
                redis.call('expire', key, 3600)
                return 0
            end
            """;

        private final RedisScript<Long> luaScript;

        public DistributedTokenBucketRateLimiter(RedisTemplate<String, String> redisTemplate,
                                               String bucketKey,
                                               long capacity,
                                               long refillRate) {
            this.redisTemplate = redisTemplate;
            this.bucketKey = bucketKey;
            this.capacity = capacity;
            this.refillRate = refillRate;
            this.luaScript = new DefaultRedisScript<>(LUA_SCRIPT, Long.class);
        }

        public boolean tryAcquire(long tokensRequested) {
            List<String> keys = Collections.singletonList(bucketKey);
            Object[] args = {
                String.valueOf(capacity),
                String.valueOf(refillRate),
                String.valueOf(tokensRequested),
                String.valueOf(System.currentTimeMillis())
            };

            Long result = redisTemplate.execute(luaScript, keys, args);
            return result != null && result == 1;
        }

        public boolean tryAcquire() {
            return tryAcquire(1);
        }
    }
}

2. 漏桶算法

漏桶算法通过固定的处理速率来平滑突发流量。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
public class LeakyBucketRateLimiter {
    private final long capacity;              // 桶容量
    private final long leakRate;             // 漏出速率(每秒)
    private volatile long currentVolume;      // 当前水量
    private volatile long lastLeakTime;      // 上次漏水时间
    private final Object lock = new Object();

    public LeakyBucketRateLimiter(long capacity, long leakRate) {
        this.capacity = capacity;
        this.leakRate = leakRate;
        this.currentVolume = 0;
        this.lastLeakTime = System.nanoTime();
    }

    // 尝试添加请求到漏桶
    public boolean tryAdd(long volume) {
        synchronized (lock) {
            leak();

            if (currentVolume + volume <= capacity) {
                currentVolume += volume;
                return true;
            }

            return false;
        }
    }

    // 尝试添加单个请求
    public boolean tryAdd() {
        return tryAdd(1);
    }

    // 漏水处理
    private void leak() {
        long currentTime = System.nanoTime();
        long timePassed = currentTime - lastLeakTime;

        if (timePassed > 0) {
            long volumeToLeak = (timePassed * leakRate) / 1_000_000_000L;
            currentVolume = Math.max(0, currentVolume - volumeToLeak);
            lastLeakTime = currentTime;
        }
    }

    // 获取当前水量
    public long getCurrentVolume() {
        synchronized (lock) {
            leak();
            return currentVolume;
        }
    }

    // 分布式漏桶实现
    public static class DistributedLeakyBucketRateLimiter {
        private final RedisTemplate<String, String> redisTemplate;
        private final String bucketKey;
        private final long capacity;
        private final long leakRate;

        private static final String LUA_SCRIPT = """
            local key = KEYS[1]
            local capacity = tonumber(ARGV[1])
            local leakRate = tonumber(ARGV[2])
            local volumeToAdd = tonumber(ARGV[3])
            local currentTime = tonumber(ARGV[4])

            local bucket = redis.call('hmget', key, 'volume', 'lastLeakTime')
            local currentVolume = tonumber(bucket[1]) or 0
            local lastLeakTime = tonumber(bucket[2]) or currentTime

            -- 计算漏出的水量
            local timePassed = math.max(0, currentTime - lastLeakTime)
            local volumeToLeak = math.floor(timePassed * leakRate / 1000)
            currentVolume = math.max(0, currentVolume - volumeToLeak)

            -- 检查是否可以添加新的水量
            if currentVolume + volumeToAdd <= capacity then
                currentVolume = currentVolume + volumeToAdd
                redis.call('hmset', key, 'volume', currentVolume, 'lastLeakTime', currentTime)
                redis.call('expire', key, 3600)
                return 1
            else
                redis.call('hmset', key, 'volume', currentVolume, 'lastLeakTime', currentTime)
                redis.call('expire', key, 3600)
                return 0
            end
            """;

        private final RedisScript<Long> luaScript;

        public DistributedLeakyBucketRateLimiter(RedisTemplate<String, String> redisTemplate,
                                               String bucketKey,
                                               long capacity,
                                               long leakRate) {
            this.redisTemplate = redisTemplate;
            this.bucketKey = bucketKey;
            this.capacity = capacity;
            this.leakRate = leakRate;
            this.luaScript = new DefaultRedisScript<>(LUA_SCRIPT, Long.class);
        }

        public boolean tryAdd(long volume) {
            List<String> keys = Collections.singletonList(bucketKey);
            Object[] args = {
                String.valueOf(capacity),
                String.valueOf(leakRate),
                String.valueOf(volume),
                String.valueOf(System.currentTimeMillis())
            };

            Long result = redisTemplate.execute(luaScript, keys, args);
            return result != null && result == 1;
        }

        public boolean tryAdd() {
            return tryAdd(1);
        }
    }
}

3. 滑动窗口算法

滑动窗口算法提供更精确的限流控制。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
public class SlidingWindowRateLimiter {
    private final long windowSizeMs;        // 窗口大小(毫秒)
    private final long maxRequests;         // 最大请求数
    private final int subWindowCount;       // 子窗口数量
    private final long subWindowSizeMs;     // 子窗口大小
    private final AtomicLongArray counters;  // 计数器数组
    private volatile long lastUpdateTime;    // 上次更新时间

    public SlidingWindowRateLimiter(long windowSizeMs, long maxRequests, int subWindowCount) {
        this.windowSizeMs = windowSizeMs;
        this.maxRequests = maxRequests;
        this.subWindowCount = subWindowCount;
        this.subWindowSizeMs = windowSizeMs / subWindowCount;
        this.counters = new AtomicLongArray(subWindowCount);
        this.lastUpdateTime = System.currentTimeMillis();
    }

    // 尝试获取许可
    public boolean tryAcquire() {
        return tryAcquire(1);
    }

    public boolean tryAcquire(long permits) {
        long currentTime = System.currentTimeMillis();

        // 清理过期的子窗口
        cleanExpiredWindows(currentTime);

        // 计算当前总请求数
        long totalRequests = getCurrentTotalRequests();

        if (totalRequests + permits <= maxRequests) {
            // 增加当前子窗口的计数
            int currentWindowIndex = getCurrentWindowIndex(currentTime);
            counters.addAndGet(currentWindowIndex, permits);
            return true;
        }

        return false;
    }

    // 清理过期的子窗口
    private void cleanExpiredWindows(long currentTime) {
        long timeDiff = currentTime - lastUpdateTime;

        if (timeDiff >= subWindowSizeMs) {
            long expiredWindows = Math.min(timeDiff / subWindowSizeMs, subWindowCount);

            for (int i = 0; i < expiredWindows; i++) {
                int indexToReset = (int) ((lastUpdateTime / subWindowSizeMs + i + 1) % subWindowCount);
                counters.set(indexToReset, 0);
            }

            lastUpdateTime = currentTime;
        }
    }

    // 获取当前窗口索引
    private int getCurrentWindowIndex(long currentTime) {
        return (int) ((currentTime / subWindowSizeMs) % subWindowCount);
    }

    // 获取当前总请求数
    private long getCurrentTotalRequests() {
        long total = 0;
        for (int i = 0; i < subWindowCount; i++) {
            total += counters.get(i);
        }
        return total;
    }

    // 获取当前窗口统计信息
    public WindowStats getWindowStats() {
        long currentTime = System.currentTimeMillis();
        cleanExpiredWindows(currentTime);

        WindowStats stats = new WindowStats();
        stats.setCurrentRequests(getCurrentTotalRequests());
        stats.setMaxRequests(maxRequests);
        stats.setWindowSizeMs(windowSizeMs);
        stats.setRemainingRequests(Math.max(0, maxRequests - stats.getCurrentRequests()));

        return stats;
    }

    public static class WindowStats {
        private long currentRequests;
        private long maxRequests;
        private long windowSizeMs;
        private long remainingRequests;

        // getter和setter方法
        public long getCurrentRequests() { return currentRequests; }
        public void setCurrentRequests(long currentRequests) { this.currentRequests = currentRequests; }

        public long getMaxRequests() { return maxRequests; }
        public void setMaxRequests(long maxRequests) { this.maxRequests = maxRequests; }

        public long getWindowSizeMs() { return windowSizeMs; }
        public void setWindowSizeMs(long windowSizeMs) { this.windowSizeMs = windowSizeMs; }

        public long getRemainingRequests() { return remainingRequests; }
        public void setRemainingRequests(long remainingRequests) { this.remainingRequests = remainingRequests; }
    }

    // 分布式滑动窗口实现
    public static class DistributedSlidingWindowRateLimiter {
        private final RedisTemplate<String, String> redisTemplate;
        private final String windowKey;
        private final long windowSizeMs;
        private final long maxRequests;
        private final int subWindowCount;

        private static final String LUA_SCRIPT = """
            local key = KEYS[1]
            local windowSizeMs = tonumber(ARGV[1])
            local maxRequests = tonumber(ARGV[2])
            local subWindowCount = tonumber(ARGV[3])
            local permits = tonumber(ARGV[4])
            local currentTime = tonumber(ARGV[5])

            local subWindowSizeMs = windowSizeMs / subWindowCount
            local currentWindowIndex = math.floor(currentTime / subWindowSizeMs) % subWindowCount

            -- 清理过期窗口
            local expiredTime = currentTime - windowSizeMs
            local members = redis.call('zrangebyscore', key, 0, expiredTime)
            if #members > 0 then
                redis.call('zremrangebyscore', key, 0, expiredTime)
            end

            -- 计算当前窗口总请求数
            local currentTotal = redis.call('zcard', key)

            if currentTotal + permits <= maxRequests then
                -- 添加新请求到有序集合
                redis.call('zadd', key, currentTime, currentTime .. ':' .. math.random())
                redis.call('expire', key, math.ceil(windowSizeMs / 1000) + 1)
                return 1
            else
                return 0
            end
            """;

        private final RedisScript<Long> luaScript;

        public DistributedSlidingWindowRateLimiter(RedisTemplate<String, String> redisTemplate,
                                                 String windowKey,
                                                 long windowSizeMs,
                                                 long maxRequests,
                                                 int subWindowCount) {
            this.redisTemplate = redisTemplate;
            this.windowKey = windowKey;
            this.windowSizeMs = windowSizeMs;
            this.maxRequests = maxRequests;
            this.subWindowCount = subWindowCount;
            this.luaScript = new DefaultRedisScript<>(LUA_SCRIPT, Long.class);
        }

        public boolean tryAcquire(long permits) {
            List<String> keys = Collections.singletonList(windowKey);
            Object[] args = {
                String.valueOf(windowSizeMs),
                String.valueOf(maxRequests),
                String.valueOf(subWindowCount),
                String.valueOf(permits),
                String.valueOf(System.currentTimeMillis())
            };

            Long result = redisTemplate.execute(luaScript, keys, args);
            return result != null && result == 1;
        }

        public boolean tryAcquire() {
            return tryAcquire(1);
        }
    }
}

统一限流框架

1. 多层级限流管理器

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
@Component
public class MultiLevelRateLimitManager {
    private final Map<String, RateLimiter> limiters;
    private final RedisTemplate<String, String> redisTemplate;

    public MultiLevelRateLimitManager(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
        this.limiters = new ConcurrentHashMap<>();
    }

    // 限流配置
    public static class RateLimitConfig {
        private String algorithm;    // TOKEN_BUCKET, LEAKY_BUCKET, SLIDING_WINDOW
        private long capacity;       // 容量
        private long rate;          // 速率
        private long windowSizeMs;  // 窗口大小(仅滑动窗口使用)
        private int subWindows;     // 子窗口数量(仅滑动窗口使用)

        // constructor和getter/setter方法
        public RateLimitConfig(String algorithm, long capacity, long rate) {
            this.algorithm = algorithm;
            this.capacity = capacity;
            this.rate = rate;
        }

        // getter和setter方法省略...
    }

    // 限流器接口
    public interface RateLimiter {
        boolean tryAcquire(long permits);
        default boolean tryAcquire() { return tryAcquire(1); }
    }

    // 创建限流器
    public RateLimiter createRateLimiter(String key, RateLimitConfig config) {
        return limiters.computeIfAbsent(key, k -> {
            switch (config.algorithm) {
                case "TOKEN_BUCKET":
                    return new TokenBucketRateLimiter.DistributedTokenBucketRateLimiter(
                            redisTemplate, "token_bucket:" + key, config.capacity, config.rate);
                case "LEAKY_BUCKET":
                    return new LeakyBucketRateLimiter.DistributedLeakyBucketRateLimiter(
                            redisTemplate, "leaky_bucket:" + key, config.capacity, config.rate);
                case "SLIDING_WINDOW":
                    return new SlidingWindowRateLimiter.DistributedSlidingWindowRateLimiter(
                            redisTemplate, "sliding_window:" + key,
                            config.windowSizeMs, config.capacity, config.subWindows);
                default:
                    throw new IllegalArgumentException("Unsupported algorithm: " + config.algorithm);
            }
        });
    }

    // 多层级限流检查
    public boolean checkRateLimit(String userId, String api, String ip) {
        // 用户级限流
        RateLimiter userLimiter = createRateLimiter(
                "user:" + userId,
                new RateLimitConfig("TOKEN_BUCKET", 1000, 10)
        );

        // API级限流
        RateLimiter apiLimiter = createRateLimiter(
                "api:" + api,
                new RateLimitConfig("LEAKY_BUCKET", 5000, 50)
        );

        // IP级限流
        RateLimiter ipLimiter = createRateLimiter(
                "ip:" + ip,
                new RateLimitConfig("SLIDING_WINDOW", 100, 10)
        );

        // 只有所有限流器都通过才允许请求
        return userLimiter.tryAcquire() &&
               apiLimiter.tryAcquire() &&
               ipLimiter.tryAcquire();
    }
}

// 限流注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
    String key() default "";
    String algorithm() default "TOKEN_BUCKET";
    long capacity() default 100;
    long rate() default 10;
    long windowSizeMs() default 60000;
    int subWindows() default 10;
    String[] dimensions() default {"user", "ip"}; // 限流维度
}

// 限流切面
@Aspect
@Component
public class RateLimitAspect {
    private final MultiLevelRateLimitManager rateLimitManager;

    public RateLimitAspect(MultiLevelRateLimitManager rateLimitManager) {
        this.rateLimitManager = rateLimitManager;
    }

    @Around("@annotation(rateLimit)")
    public Object enforceRateLimit(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
        HttpServletRequest request = getCurrentRequest();
        String userId = (String) request.getAttribute("userId");
        String ip = getClientIP(request);
        String api = joinPoint.getSignature().getName();

        // 构建限流key
        String key = buildRateLimitKey(rateLimit.key(), userId, ip, api);

        // 创建限流配置
        MultiLevelRateLimitManager.RateLimitConfig config =
                new MultiLevelRateLimitManager.RateLimitConfig(
                        rateLimit.algorithm(),
                        rateLimit.capacity(),
                        rateLimit.rate()
                );
        if ("SLIDING_WINDOW".equals(rateLimit.algorithm())) {
            config.setWindowSizeMs(rateLimit.windowSizeMs());
            config.setSubWindows(rateLimit.subWindows());
        }

        // 检查限流
        MultiLevelRateLimitManager.RateLimiter limiter =
                rateLimitManager.createRateLimiter(key, config);

        if (!limiter.tryAcquire()) {
            throw new RateLimitExceededException("Rate limit exceeded for key: " + key);
        }

        return joinPoint.proceed();
    }

    private String buildRateLimitKey(String baseKey, String userId, String ip, String api) {
        if (!baseKey.isEmpty()) {
            return baseKey;
        }
        return String.format("%s:%s:%s", api, userId != null ? userId : "anonymous", ip);
    }

    private HttpServletRequest getCurrentRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes instanceof ServletRequestAttributes) {
            return ((ServletRequestAttributes) requestAttributes).getRequest();
        }
        throw new IllegalStateException("No current HTTP request");
    }

    private String getClientIP(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.split(",")[0].trim();
        }
        String xRealIP = request.getHeader("X-Real-IP");
        if (xRealIP != null && !xRealIP.isEmpty()) {
            return xRealIP;
        }
        return request.getRemoteAddr();
    }
}

// 限流异常
public class RateLimitExceededException extends RuntimeException {
    public RateLimitExceededException(String message) {
        super(message);
    }
}

性能监控和指标

1. 安全监控系统

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
@Component
public class SecurityMonitoringService {
    private final MeterRegistry meterRegistry;
    private final RedisTemplate<String, String> redisTemplate;
    private final Timer authTimer;
    private final Counter authSuccessCounter;
    private final Counter authFailureCounter;
    private final Counter rateLimitCounter;

    public SecurityMonitoringService(MeterRegistry meterRegistry,
                                   RedisTemplate<String, String> redisTemplate) {
        this.meterRegistry = meterRegistry;
        this.redisTemplate = redisTemplate;
        this.authTimer = Timer.builder("auth.duration")
                .description("Authentication duration")
                .register(meterRegistry);
        this.authSuccessCounter = Counter.builder("auth.success")
                .description("Successful authentications")
                .register(meterRegistry);
        this.authFailureCounter = Counter.builder("auth.failure")
                .description("Failed authentications")
                .register(meterRegistry);
        this.rateLimitCounter = Counter.builder("ratelimit.exceeded")
                .description("Rate limit exceeded events")
                .register(meterRegistry);
    }

    // 记录认证事件
    public void recordAuthEvent(String userId, String ip, boolean success, long duration) {
        Timer.Sample sample = Timer.start(meterRegistry);
        sample.stop(authTimer);

        if (success) {
            authSuccessCounter.increment(
                    Tags.of(
                            Tag.of("user_id", userId),
                            Tag.of("ip", ip)
                    )
            );
        } else {
            authFailureCounter.increment(
                    Tags.of(
                            Tag.of("user_id", userId != null ? userId : "unknown"),
                            Tag.of("ip", ip)
                    )
            );

            // 记录失败尝试
            recordFailedAttempt(ip, userId);
        }
    }

    // 记录限流事件
    public void recordRateLimitEvent(String key, String algorithm) {
        rateLimitCounter.increment(
                Tags.of(
                        Tag.of("key", key),
                        Tag.of("algorithm", algorithm)
                )
        );
    }

    // 记录失败尝试
    private void recordFailedAttempt(String ip, String userId) {
        String key = "failed_attempts:" + ip;
        String countStr = redisTemplate.opsForValue().get(key);
        int count = countStr != null ? Integer.parseInt(countStr) : 0;
        count++;

        redisTemplate.opsForValue().set(key, String.valueOf(count), Duration.ofMinutes(15));

        // 如果失败次数过多,触发告警
        if (count >= 5) {
            triggerSecurityAlert("Multiple failed attempts", ip, userId, count);
        }
    }

    // 触发安全告警
    private void triggerSecurityAlert(String alertType, String ip, String userId, int count) {
        SecurityAlert alert = new SecurityAlert();
        alert.setAlertType(alertType);
        alert.setIp(ip);
        alert.setUserId(userId);
        alert.setCount(count);
        alert.setTimestamp(System.currentTimeMillis());

        // 发送告警(可以通过消息队列、邮件、短信等方式)
        System.out.printf("SECURITY ALERT: %s from IP %s (User: %s, Count: %d)%n",
                         alertType, ip, userId, count);
    }

    public static class SecurityAlert {
        private String alertType;
        private String ip;
        private String userId;
        private int count;
        private long timestamp;

        // getter和setter方法省略...
    }

    // 获取安全统计信息
    public SecurityStats getSecurityStats() {
        SecurityStats stats = new SecurityStats();

        // 获取认证统计
        stats.setTotalAuthAttempts(
                (long) (authSuccessCounter.count() + authFailureCounter.count())
        );
        stats.setSuccessfulAuths((long) authSuccessCounter.count());
        stats.setFailedAuths((long) authFailureCounter.count());
        stats.setRateLimitExceeded((long) rateLimitCounter.count());

        // 计算成功率
        if (stats.getTotalAuthAttempts() > 0) {
            stats.setSuccessRate(
                    (double) stats.getSuccessfulAuths() / stats.getTotalAuthAttempts()
            );
        }

        return stats;
    }

    public static class SecurityStats {
        private long totalAuthAttempts;
        private long successfulAuths;
        private long failedAuths;
        private long rateLimitExceeded;
        private double successRate;

        // getter和setter方法省略...
    }
}

应用场景和最佳实践

应用场景

  1. API网关:统一入口的身份认证和限流
  2. 微服务治理:服务间调用的安全控制
  3. 移动应用后端:用户认证和API保护
  4. IoT平台:设备认证和数据传输控制
  5. 金融系统:高安全性要求的交易保护

最佳实践

  1. 认证策略

    • 使用JWT进行无状态认证
    • 实现Token刷新机制
    • 支持多种认证方式
  2. 限流策略

    • 根据业务特点选择合适的算法
    • 实现多维度限流
    • 提供限流降级机制
  3. 安全监控

    • 实时监控异常行为
    • 建立告警机制
    • 记录详细的安全日志

性能对比

算法突发处理能力平滑程度实现复杂度适用场景
令牌桶中等中等允许突发流量
漏桶简单流量平滑
滑动窗口中等复杂精确控制

总结

微服务架构中的鉴权限流机制通过精巧的数据结构和算法设计,实现了:

  1. 身份认证:JWT、OAuth2等无状态认证机制
  2. 权限控制:RBAC、ABAC等细粒度权限模型
  3. 流量控制:令牌桶、漏桶、滑动窗口等限流算法
  4. 安全监控:实时监控、异常检测、告警机制

这些技术的合理组合和实施,为微服务系统提供了全面的安全保障,确保系统在高并发场景下的稳定性和安全性。理解这些底层原理,有助于构建更加健壮和高效的微服务安全体系。