SecurityUtil.java

package com.yumu.noveltranslator.util;

import com.yumu.noveltranslator.adapter.out.security.CustomUserDetails;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;

import java.util.Optional;

/**
 * 安全认证工具类
 * 统一处理 Controller 中的认证代码提取
 */
public final class SecurityUtil {

    private SecurityUtil() {
    }

    /**
     * 获取当前认证用户ID,如果未认证则返回空
     */
    public static Optional<Long> getCurrentUserId() {
        return getCurrentUserDetails().map(CustomUserDetails::getId);
    }

    /**
     * 获取当前认证用户的 userLevel,如果未认证则返回空
     */
    public static Optional<String> getCurrentUserLevel() {
        return getCurrentUserDetails().map(CustomUserDetails::getUserLevel);
    }

    /**
     * 获取当前认证用户详情,如果未认证则返回空
     */
    public static Optional<CustomUserDetails> getCurrentUserDetails() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof CustomUserDetails) {
            return Optional.of((CustomUserDetails) authentication.getPrincipal());
        }
        return Optional.empty();
    }

    /**
     * 获取当前认证用户ID,如果未认证则抛出异常
     */
    public static Long getRequiredUserId() {
        return getRequiredUserDetails().getId();
    }

    /**
     * 获取当前认证用户详情,如果未认证则抛出异常
     */
    public static CustomUserDetails getRequiredUserDetails() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !(authentication.getPrincipal() instanceof CustomUserDetails)) {
            throw new IllegalStateException("未认证的用户");
        }
        return (CustomUserDetails) authentication.getPrincipal();
    }

    /**
     * 从 Authorization header 中解析 Bearer token
     * @return token 字符串,如果没有或格式不对则返回 null
     */
    public static String parseBearerToken(HttpServletRequest request) {
        return parseBearerToken(request.getHeader("Authorization"));
    }

    /**
     * 从 Authorization header 字符串中解析 Bearer token
     */
    public static String parseBearerToken(String authHeader) {
        if (StringUtils.hasText(authHeader) && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7);
        }
        return null;
    }

    /**
     * 提取真实客户端 IP,检查代理头
     */
    public static String getClientIp(HttpServletRequest request) {
        String xff = request.getHeader("X-Forwarded-For");
        if (StringUtils.hasText(xff)) {
            return xff.split(",")[0].trim();
        }
        String xri = request.getHeader("X-Real-IP");
        if (StringUtils.hasText(xri)) {
            return xri.trim();
        }
        return request.getRemoteAddr();
    }

    /**
     * 掩码 API Key(显示前6位 + "****" + 后4位)
     */
    public static String maskApiKey(String key) {
        if (key == null || key.length() < 16) return "***";
        return key.substring(0, 6) + "****" + key.substring(key.length() - 4);
    }

    /**
     * 获取当前用户 ID 字符串,未认证时返回 "anonymous"
     */
    public static String getCurrentUserIdOrAnonymous() {
        return getCurrentUserDetails()
                .map(userDetails -> "user_" + userDetails.getId())
                .orElse("anonymous");
    }

    /**
     * 获取当前用户等级,未认证时返回 "anonymous"
     */
    public static String getCurrentUserLevelOrDefault() {
        return getCurrentUserDetails()
                .map(CustomUserDetails::getUserLevel)
                .orElse("anonymous");
    }
}