# 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");
        }
    }