前后端分离架构下的API安全防护体系:认证授权与数据保护实战

Zane225
Zane225 2026-02-10T05:10:05+08:00
0 0 0

引言

随着前后端分离架构的广泛应用,API作为系统间通信的核心接口,其安全性变得尤为重要。传统的单体应用架构中,认证授权往往通过Session机制实现,而在前后端分离的场景下,这种模式已无法满足现代Web应用的需求。本文将深入探讨在前后端分离架构下构建完整API安全防护体系的技术方案,涵盖JWT令牌认证、OAuth2授权、接口签名验证、数据加密传输等核心技术。

一、前后端分离架构下的安全挑战

1.1 架构特点与安全需求

前后端分离架构将前端应用和后端服务完全解耦,前端通过HTTP API与后端进行通信。这种架构的优势在于提高了开发效率、便于维护和扩展,但也带来了新的安全挑战:

  • 认证状态管理:传统Session机制无法在无状态的RESTful API中直接使用
  • 跨域访问控制:浏览器同源策略限制了不同域名间的API调用
  • 数据传输安全:敏感信息在网络传输过程中面临被截获的风险
  • 接口访问控制:需要精确控制不同用户对不同接口的访问权限

1.2 常见安全威胁分析

在前后端分离架构中,API面临的主要安全威胁包括:

  • 未授权访问:缺乏有效的认证机制导致恶意用户可以随意访问API
  • 数据泄露:敏感信息在传输和存储过程中未得到有效保护
  • 接口滥用:恶意用户通过频繁调用API消耗系统资源
  • 中间人攻击:网络传输过程中数据被截获或篡改

二、JWT令牌认证机制详解

2.1 JWT基本原理

JSON Web Token (JWT) 是一种开放标准(RFC 7519),用于在各方之间安全地传输信息。JWT由三部分组成:

xxxxx.yyyyy.zzzzz
  • Header:包含令牌类型和签名算法信息
  • Payload:包含声明(claims)信息,如用户ID、角色等
  • Signature:用于验证令牌完整性的签名

2.2 JWT实现代码示例

// 前端登录认证示例
const login = async (username, password) => {
    try {
        const response = await fetch('/api/auth/login', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                username,
                password
            })
        });
        
        const data = await response.json();
        if (data.token) {
            // 存储JWT令牌
            localStorage.setItem('authToken', data.token);
            return true;
        }
        return false;
    } catch (error) {
        console.error('登录失败:', error);
        return false;
    }
};

// API请求拦截器
const apiRequest = async (url, options = {}) => {
    const token = localStorage.getItem('authToken');
    
    const defaultOptions = {
        headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${token}`
        }
    };
    
    const mergedOptions = { ...defaultOptions, ...options };
    
    try {
        const response = await fetch(url, mergedOptions);
        if (response.status === 401) {
            // Token过期,清除本地存储并跳转到登录页
            localStorage.removeItem('authToken');
            window.location.href = '/login';
        }
        return response.json();
    } catch (error) {
        throw new Error('网络请求失败');
    }
};
// 后端JWT认证实现
@RestController
@RequestMapping("/api/auth")
public class AuthController {
    
    @Autowired
    private JwtTokenProvider jwtTokenProvider;
    
    @Autowired
    private UserService userService;
    
    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest request) {
        try {
            // 验证用户凭据
            User user = userService.authenticate(request.getUsername(), request.getPassword());
            
            if (user != null) {
                // 生成JWT令牌
                String token = jwtTokenProvider.generateToken(user);
                
                return ResponseEntity.ok(new AuthResponse(token, user.getUsername()));
            }
            
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                .body("用户名或密码错误");
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body("登录失败");
        }
    }
}

// JWT工具类
@Component
public class JwtTokenProvider {
    
    private String secretKey = "mySecretKey1234567890";
    private int validityInMilliseconds = 3600000; // 1小时
    
    public String generateToken(User user) {
        Claims claims = Jwts.claims().setSubject(user.getUsername());
        claims.put("roles", user.getRoles());
        claims.put("userId", user.getId());
        
        Date now = new Date();
        Date validity = new Date(now.getTime() + validityInMilliseconds);
        
        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .setExpiration(validity)
                .signWith(SignatureAlgorithm.HS512, secretKey)
                .compact();
    }
    
    public String getUsername(String token) {
        return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
    }
    
    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            return false;
        }
    }
}

2.3 JWT安全最佳实践

  1. 密钥管理:使用强加密算法和安全的密钥存储机制
  2. 令牌过期:设置合理的令牌有效期,避免长期有效令牌
  3. 刷新机制:实现令牌刷新机制,提高安全性
  4. 敏感信息处理:避免在JWT中包含敏感信息

三、OAuth2授权框架集成

3.1 OAuth2核心概念

OAuth2是一种开放的授权标准,允许第三方应用在用户授权的情况下访问资源服务器上的资源。主要角色包括:

  • 资源所有者:用户
  • 客户端:第三方应用
  • 资源服务器:提供受保护资源的服务器
  • 授权服务器:验证用户身份并颁发令牌

3.2 授权码模式实现

// OAuth2授权控制器
@RestController
@RequestMapping("/oauth2")
public class OAuth2Controller {
    
    @Autowired
    private AuthorizationService authorizationService;
    
    @GetMapping("/authorize")
    public void authorize(
            @RequestParam String response_type,
            @RequestParam String client_id,
            @RequestParam String redirect_uri,
            @RequestParam(required = false) String scope,
            @RequestParam(required = false) String state,
            HttpServletResponse response) throws IOException {
        
        // 验证客户端
        if (!authorizationService.isValidClient(client_id)) {
            response.sendError(400, "无效的客户端");
            return;
        }
        
        // 重定向到登录页面或直接授权
        if (isUserAuthenticated()) {
            String authorizationCode = authorizationService.generateAuthorizationCode();
            String redirectUrl = redirect_uri + "?code=" + authorizationCode + "&state=" + state;
            response.sendRedirect(redirectUrl);
        } else {
            // 重定向到登录页面
            response.sendRedirect("/login?redirect_uri=" + redirect_uri);
        }
    }
    
    @PostMapping("/token")
    public ResponseEntity<?> token(
            @RequestParam String grant_type,
            @RequestParam String code,
            @RequestParam String client_id,
            @RequestParam String client_secret,
            @RequestParam(required = false) String redirect_uri) {
        
        try {
            // 验证客户端凭据
            if (!authorizationService.validateClient(client_id, client_secret)) {
                return ResponseEntity.status(401).body("无效的客户端凭据");
            }
            
            // 验证授权码
            if (!authorizationService.validateAuthorizationCode(code)) {
                return ResponseEntity.status(400).body("无效的授权码");
            }
            
            // 生成访问令牌
            String accessToken = authorizationService.generateAccessToken();
            String refreshToken = authorizationService.generateRefreshToken();
            
            Map<String, Object> tokenResponse = new HashMap<>();
            tokenResponse.put("access_token", accessToken);
            tokenResponse.put("token_type", "Bearer");
            tokenResponse.put("expires_in", 3600);
            tokenResponse.put("refresh_token", refreshToken);
            
            return ResponseEntity.ok(tokenResponse);
        } catch (Exception e) {
            return ResponseEntity.status(500).body("令牌生成失败");
        }
    }
}

3.3 前端OAuth2集成示例

// OAuth2授权登录
const oauth2Login = () => {
    const clientId = 'your_client_id';
    const redirectUri = encodeURIComponent('http://localhost:3000/callback');
    const authUrl = `https://oauth2.example.com/oauth2/authorize?response_type=code&client_id=${clientId}&redirect_uri=${redirectUri}&scope=read`;
    
    window.location.href = authUrl;
};

// 处理授权回调
const handleOAuth2Callback = async () => {
    const urlParams = new URLSearchParams(window.location.search);
    const code = urlParams.get('code');
    const state = urlParams.get('state');
    
    if (code) {
        try {
            // 交换授权码获取访问令牌
            const response = await fetch('/api/oauth2/token', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    grant_type: 'authorization_code',
                    code: code,
                    client_id: 'your_client_id',
                    client_secret: 'your_client_secret',
                    redirect_uri: 'http://localhost:3000/callback'
                })
            });
            
            const data = await response.json();
            if (data.access_token) {
                localStorage.setItem('oauth2Token', data.access_token);
                window.location.href = '/dashboard';
            }
        } catch (error) {
            console.error('OAuth2授权失败:', error);
        }
    }
};

四、接口签名验证机制

4.1 签名算法原理

接口签名是通过特定算法对请求参数进行加密处理,确保请求的完整性和真实性。常见的签名算法包括:

  • HMAC-SHA256:基于密钥的哈希消息认证码
  • MD5:消息摘要算法
  • SHA-1/SHA-256:安全哈希算法

4.2 签名实现代码

// 签名工具类
@Component
public class ApiSignatureUtil {
    
    private static final String SECRET_KEY = "your_secret_key_1234567890";
    private static final String SIGNATURE_HEADER = "X-Signature";
    private static final String TIMESTAMP_HEADER = "X-Timestamp";
    
    public String generateSignature(Map<String, Object> params, String method, String uri) {
        // 1. 参数排序
        List<String> sortedKeys = new ArrayList<>(params.keySet());
        Collections.sort(sortedKeys);
        
        // 2. 构造签名字符串
        StringBuilder signStr = new StringBuilder();
        signStr.append(method).append(uri);
        
        for (String key : sortedKeys) {
            Object value = params.get(key);
            if (value != null) {
                signStr.append(key).append(value.toString());
            }
        }
        
        // 3. 添加时间戳
        long timestamp = System.currentTimeMillis() / 1000;
        signStr.append("timestamp").append(timestamp);
        
        // 4. 添加密钥并生成签名
        signStr.append(SECRET_KEY);
        
        return DigestUtils.sha256Hex(signStr.toString());
    }
    
    public boolean verifySignature(HttpServletRequest request) {
        try {
            String signature = request.getHeader(SIGNATURE_HEADER);
            String timestamp = request.getHeader(TIMESTAMP_HEADER);
            
            if (signature == null || timestamp == null) {
                return false;
            }
            
            // 验证时间戳(防止重放攻击)
            long timeDiff = Math.abs(System.currentTimeMillis() / 1000 - Long.parseLong(timestamp));
            if (timeDiff > 300) { // 5分钟有效期
                return false;
            }
            
            // 重新计算签名并验证
            Map<String, String[]> parameterMap = request.getParameterMap();
            Map<String, Object> params = new HashMap<>();
            
            for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
                if (entry.getValue() != null && entry.getValue().length > 0) {
                    params.put(entry.getKey(), entry.getValue()[0]);
                }
            }
            
            // 移除签名和时间戳参数
            params.remove(SIGNATURE_HEADER);
            params.remove(TIMESTAMP_HEADER);
            
            String calculatedSignature = generateSignature(params, request.getMethod(), request.getRequestURI());
            return signature.equals(calculatedSignature);
            
        } catch (Exception e) {
            return false;
        }
    }
}

// 签名拦截器
@Component
public class ApiSignatureInterceptor implements HandlerInterceptor {
    
    @Autowired
    private ApiSignatureUtil signatureUtil;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (request.getMethod().equals("GET")) {
            // GET请求验证签名
            if (!signatureUtil.verifySignature(request)) {
                response.setStatus(401);
                response.getWriter().write("{\"error\": \"签名验证失败\"}");
                return false;
            }
        }
        return true;
    }
}

4.3 前端签名生成示例

// API请求签名工具
class ApiSignature {
    static SECRET_KEY = 'your_secret_key_1234567890';
    
    static generateSignature(params, method, url) {
        // 参数排序
        const sortedParams = Object.keys(params)
            .sort()
            .reduce((obj, key) => {
                obj[key] = params[key];
                return obj;
            }, {});
        
        // 构造签名字符串
        let signStr = `${method}${url}`;
        Object.keys(sortedParams).forEach(key => {
            signStr += `${key}${sortedParams[key]}`;
        });
        
        // 添加时间戳
        const timestamp = Math.floor(Date.now() / 1000);
        signStr += `timestamp${timestamp}`;
        
        // 添加密钥并生成签名
        signStr += this.SECRET_KEY;
        
        return CryptoJS.SHA256(signStr).toString();
    }
    
    static async request(url, options = {}) {
        const timestamp = Math.floor(Date.now() / 1000);
        const params = { ...options.params };
        
        // 添加时间戳
        params.timestamp = timestamp;
        
        // 生成签名
        const signature = this.generateSignature(params, options.method || 'GET', url);
        
        const defaultOptions = {
            headers: {
                'X-Signature': signature,
                'X-Timestamp': timestamp.toString(),
                'Content-Type': 'application/json'
            }
        };
        
        const mergedOptions = { ...defaultOptions, ...options };
        
        try {
            const response = await fetch(url, mergedOptions);
            return response.json();
        } catch (error) {
            throw new Error('API请求失败');
        }
    }
}

// 使用示例
const apiCall = async () => {
    try {
        const result = await ApiSignature.request('/api/users', {
            method: 'POST',
            body: JSON.stringify({
                name: 'John Doe',
                email: 'john@example.com'
            })
        });
        console.log(result);
    } catch (error) {
        console.error('请求失败:', error);
    }
};

五、数据加密传输机制

5.1 HTTPS安全传输

HTTPS是HTTP的安全版本,通过SSL/TLS协议对数据进行加密传输。在前后端分离架构中,确保所有API调用都通过HTTPS进行:

// Spring Boot配置HTTPS
@Configuration
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.requiresChannel(channel -> 
            channel.requestMatchers(r -> r.getHeader("X-Forwarded-Proto") != null)
                .requiresSecure()
        );
        
        // 其他安全配置...
        return http.build();
    }
    
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**")
                    .allowedOrigins("https://yourdomain.com")
                    .allowedMethods("GET", "POST", "PUT", "DELETE")
                    .allowCredentials(true);
            }
        };
    }
}

5.2 敏感数据加密

// 数据加密工具类
@Component
public class DataEncryptionUtil {
    
    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
    private static final String SECRET_KEY = "your_aes_key_16_bytes_long"; // 16字节
    
    public String encrypt(String plainText) throws Exception {
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        
        SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }
    
    public String decrypt(String encryptedText) throws Exception {
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        
        SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
        return new String(decryptedBytes);
    }
    
    // 敏感信息处理
    public Map<String, Object> encryptSensitiveData(Map<String, Object> data) {
        Map<String, Object> encryptedData = new HashMap<>();
        
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            if (isSensitiveField(entry.getKey())) {
                try {
                    String encryptedValue = encrypt(entry.getValue().toString());
                    encryptedData.put(entry.getKey(), encryptedValue);
                } catch (Exception e) {
                    encryptedData.put(entry.getKey(), entry.getValue());
                }
            } else {
                encryptedData.put(entry.getKey(), entry.getValue());
            }
        }
        
        return encryptedData;
    }
    
    private boolean isSensitiveField(String fieldName) {
        Set<String> sensitiveFields = Set.of("password", "credit_card", "ssn", "phone");
        return sensitiveFields.contains(fieldName.toLowerCase());
    }
}

5.3 前端数据保护

// 前端敏感数据处理
class DataProtection {
    static SECRET_KEY = 'frontend_encryption_key';
    
    // AES加密
    static async encrypt(text) {
        const encoder = new TextEncoder();
        const data = encoder.encode(text);
        
        const key = await crypto.subtle.importKey(
            'raw',
            this.stringToArrayBuffer(this.SECRET_KEY),
            { name: 'AES-GCM' },
            false,
            ['encrypt']
        );
        
        const iv = crypto.getRandomValues(new Uint8Array(12));
        const encrypted = await crypto.subtle.encrypt(
            {
                name: 'AES-GCM',
                iv: iv
            },
            key,
            data
        );
        
        // 将IV和加密数据组合
        const result = new Uint8Array(iv.length + encrypted.byteLength);
        result.set(iv, 0);
        result.set(new Uint8Array(encrypted), iv.length);
        
        return btoa(String.fromCharCode(...result));
    }
    
    // 字符串转数组缓冲区
    static stringToArrayBuffer(str) {
        const encoder = new TextEncoder();
        return encoder.encode(str);
    }
    
    // 敏感数据处理
    static processSensitiveData(data) {
        const sensitiveFields = ['password', 'creditCard', 'ssn'];
        const processedData = { ...data };
        
        sensitiveFields.forEach(field => {
            if (processedData[field]) {
                try {
                    processedData[field] = this.encrypt(processedData[field]);
                } catch (error) {
                    console.warn(`加密${field}字段失败`, error);
                }
            }
        });
        
        return processedData;
    }
}

// 使用示例
const submitForm = async () => {
    const formData = {
        username: 'john_doe',
        password: 'secure_password_123',
        email: 'john@example.com'
    };
    
    // 处理敏感数据
    const processedData = DataProtection.processSensitiveData(formData);
    
    try {
        const response = await fetch('/api/users', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(processedData)
        });
        
        const result = await response.json();
        console.log('提交成功:', result);
    } catch (error) {
        console.error('提交失败:', error);
    }
};

六、访问控制与权限管理

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

// 角色权限实体类
@Entity
@Table(name = "roles")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Enumerated(EnumType.STRING)
    @Column(unique = true)
    private RoleName name;
    
    @ManyToMany(mappedBy = "roles")
    private Set<User> users;
    
    // 构造函数、getter、setter
}

// 权限注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("hasRole('ADMIN')")
public @interface AdminOnly {
}

// 权限检查拦截器
@Component
public class PermissionInterceptor implements HandlerInterceptor {
    
    @Autowired
    private UserService userService;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod method = (HandlerMethod) handler;
            
            // 检查方法级别的权限注解
            if (method.hasMethodAnnotation(AdminOnly.class)) {
                String token = extractToken(request);
                if (!isUserInRole(token, "ADMIN")) {
                    response.setStatus(403);
                    response.getWriter().write("{\"error\": \"权限不足\"}");
                    return false;
                }
            }
        }
        return true;
    }
    
    private boolean isUserInRole(String token, String role) {
        try {
            // 解析JWT令牌获取用户角色
            Claims claims = Jwts.parser()
                .setSigningKey("your_secret_key")
                .parseClaimsJws(token)
                .getBody();
                
            List<String> roles = (List<String>) claims.get("roles");
            return roles != null && roles.contains(role);
        } catch (Exception e) {
            return false;
        }
    }
}

6.2 动态权限配置

// 权限管理服务
@Service
public class PermissionService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private RoleRepository roleRepository;
    
    @Autowired
    private PermissionRepository permissionRepository;
    
    // 动态分配权限
    public void assignPermissionToUser(Long userId, String permissionName) {
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
            
        Permission permission = permissionRepository.findByName(permissionName)
            .orElseGet(() -> {
                Permission newPerm = new Permission();
                newPerm.setName(permissionName);
                return permissionRepository.save(newPerm);
            });
            
        user.getPermissions().add(permission);
        userRepository.save(user);
    }
    
    // 检查用户权限
    public boolean hasPermission(String username, String permission) {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
            
        return user.getPermissions().stream()
            .anyMatch(p -> p.getName().equals(permission));
    }
    
    // 权限缓存优化
    @Cacheable(value = "user_permissions", key = "#username")
    public Set<String> getUserPermissions(String username) {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new RuntimeException("用户不存在"));
            
        return user.getRoles().stream()
            .flatMap(role -> role.getPermissions().stream())
            .map(Permission::getName)
            .collect(Collectors.toSet());
    }
}

七、安全监控与日志审计

7.1 API访问日志记录

// 安全日志记录器
@Component
public class SecurityLogger {
    
    private static final Logger logger = LoggerFactory.getLogger(SecurityLogger.class);
    
    // 记录API访问日志
    public void logApiAccess(String username, String method, String uri, 
                           Map<String, Object> requestParams, int responseStatus) {
        Map<String, Object> logData = new HashMap<>();
        logData.put("timestamp", System.currentTimeMillis());
        logData.put("username", username);
        logData.put("method", method);
        logData.put("uri", uri);
        logData.put("params", requestParams);
        logData.put("status", responseStatus);
        logData.put("ip", getClientIpAddress());
        
        logger.info("API访问日志: {}", logData.toString());
    }
    
    // 记录安全事件
    public void logSecurityEvent(String eventType, String username, String description) {
        Map<String, Object> event = new HashMap<>();
        event.put("timestamp", System.currentTimeMillis());
        event.put("eventType", eventType);
        event.put("username", username);
        event.put("description", description);
        event.put("ip", getClientIpAddress());
        
        logger.warn("安全事件: {}", event.toString());
    }
    
    private String getClientIpAddress() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
            .currentRequestAttributes()).getRequest();
        String ip = request.getHeader("X-Forwarded-For");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            return ip.split(",")[0];
        }
        return request.getRemoteAddr();
    }
}

7.2 异常检测与防护

// 安全防护拦截器
@Component
public class SecurityInterceptor implements HandlerInterceptor {
    
    private static final Map<String, Integer> requestCount = new ConcurrentHashMap<>();
    private static final Map<String, Long> lastRequestTime = new ConcurrentHashMap<>();
    
    @Autowired
    private SecurityLogger securityLogger;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String clientIp = getClientIpAddress(request);
        String uri = request.getRequestURI();
        String method = request.getMethod();
        
        // 速率限制检查
        if (!rateLimitCheck(clientIp, uri, method)) {
            response.setStatus(429); // Too Many Requests
            response.getWriter().write("{\"error\": \"请求过于频繁\"}");
            return false;
        }
        
        // 记录访问日志
        securityLogger.logApiAccess(
            getCurrentUsername(request),
            method,
            uri,
            getRequestParameters(request),
            200
        );
        
        return true;
    }
    
    private boolean rateLimitCheck(String clientIp, String uri, String method) {
        String key = clientIp + ":" + uri + ":" + method;
        long
相关推荐
广告位招租

相似文章

    评论 (0)

    0/2000