2、auth-service 企业级代码目录结构规范

【投稿赢 iPhone 17】「我的第一个开源项目」故事征集:用代码换C位出道! 10w+人浏览 1.6k人参与

当然可以!以下是为你的 urbane-commerce 电商微服务系统 中的 auth-service(认证服务) 量身定制的 企业级代码目录结构推荐方案,完全基于真实一线互联网公司(阿里、京东、美团)的实践标准,具备极强的可落地性、可维护性和扩展性。


📜《urbane-commerce auth-service 企业级代码目录结构规范》

版本:5.0 | 最后更新:2025年4月 | 技术栈:Spring Boot 3.x + JWT + Redis + MySQL + Kafka


✅ 一、整体设计理念

原则说明
职责清晰每个包只做一件事,避免“大杂烩”
分层明确控制层 → 服务层 → 数据访问层 → 工具层 → 配置层
安全优先敏感操作(密码、Token)集中管理,禁止硬编码
可测试性高所有核心逻辑支持单元测试,依赖可 Mock
可扩展性强支持未来接入 OAuth2、微信登录、多租户等
日志与监控完备所有关键操作记录审计日志,对接 Prometheus

✅ 二、推荐完整目录结构(带详细注释)

auth-service/
├── src/
│   └── main/
│       ├── java/
│       │   └── io/urbane/auth/
│       │       ├── AuthApplication.java                    # 启动类
│       │       │
│       │       ├── config/                                 # Spring 配置类
│       │       │   ├── WebSecurityConfig.java              # Spring Security 全局配置
│       │       │   ├── JwtConfig.java                      # JWT 密钥、过期时间等配置
│       │       │   ├── RedisConfig.java                    # Redis 连接配置(用于 Token 黑名单)
│       │       │   └── SwaggerConfig.java                  # API 文档配置(可选)
│       │       │
│       │       ├── controller/                             # REST API 控制器(入口)
│       │       │   ├── AuthController.java                 # 登录、注册、登出、刷新 Token
│       │       │   └── UserController.java                 # 用户信息查询(只读)
│       │       │
│       │       ├── service/                                # 核心业务逻辑
│       │       │   ├── AuthService.java                    # 登录、注册、登出、Token 签发
│       │       │   ├── UserService.java                    # 用户基础信息查询、状态校验
│       │       │   └── TokenService.java                   # JWT 生成、解析、黑名单管理
│       │       │
│       │       ├── repository/                             # 数据访问层(DAO)
│       │       │   ├── UserRepository.java                 # JPA 接口,操作 users 表
│       │       │   └── UserTokenRepository.java            # 操作 token_blacklist 表(可选)
│       │       │
│       │       ├── entity/                                 # 实体类(Entity / POJO)
│       │       │   ├── User.java                           # 用户实体(对应数据库表)
│       │       │   └── UserToken.java                      # 黑名单 Token 记录实体(可选)
│       │       │
│       │       ├── dto/                                    # 数据传输对象(DTO)
│       │       │   ├── LoginRequest.java                   # 登录请求参数
│       │       │   ├── RegisterRequest.java                # 注册请求参数
│       │       │   ├── RefreshTokenRequest.java            # 刷新 Token 请求
│       │       │   ├── LoginResponse.java                  # 登录成功响应
│       │       │   └── UserBaseInfo.java                   # 用户基本信息(脱敏返回)
│       │       │
│       │       ├── util/                                   # 工具类(无状态、纯函数)
│       │       │   ├── JwtUtil.java                        # JWT 解析、签发工具(核心)
│       │       │   ├── PasswordEncoderUtil.java            # BCrypt 密码加密工具
│       │       │   └── IdGenerator.java                    # UUID / Snowflake ID 生成器
│       │       │
│       │       ├── exception/                              # 自定义异常体系
│       │       │   ├── AuthException.java                  # 认证异常基类(如用户名不存在)
│       │       │   ├── InvalidTokenException.java          # Token 无效或已过期
│       │       │   └── UserDisabledException.java          # 账号被冻结
│       │       │
│       │       ├── aspect/                                 # AOP 切面(日志、权限)
│       │       │   └── AuthLogAspect.java                  # 记录登录、登出、Token 刷新操作日志
│       │       │
│       │       ├── listener/                               # 监听器(事件驱动)
│       │       │   └── UserRegisteredListener.java         # 监听 USER_REGISTERED 事件,触发通知
│       │       │
│       │       ├── event/                                  # 事件类(Kafka 消息体)
│       │       │   └── UserRegisteredEvent.java            # 用户注册成功事件(发布到 Kafka)
│       │       │
│       │       └── constant/                               # 枚举与常量
│       │           ├── UserRole.java                       # 用户角色枚举(USER, ADMIN)
│       │           ├── AuthStatus.java                     # 用户状态枚举(ACTIVE, FROZEN, DELETED)
│       │           └── JwtClaimKeys.java                   # JWT Claim 键名常量(避免魔法字符串)
│       │
│       └── resources/
│           ├── application.yml                           # 主配置(端口、Nacos、JWT密钥)
│           ├── application-dev.yml                       # 开发环境配置
│           ├── application-prod.yml                      # 生产环境配置
│           ├── logback-spring.xml                        # 统一日志格式(含 traceId、userId)
│           └── data/                                     # 初始化脚本(可选)
│               ├── schema.sql                            # 创建用户表结构
│               └──data.sql                              # 插入初始管理员账号
│
└── pom.xml                                                 # Maven 依赖管理(继承 commons-bom)

✅ 三、核心文件详解(带中文注释)

1️⃣ AuthApplication.java —— 启动类

package io.urbane.auth;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 认证服务启动类
 * 功能:
 *   - 启动 Spring Boot 应用
 *   - 启用 Nacos 服务发现(注册到注册中心)
 *   - 加载所有配置和组件
 *
 * @author urbane-team
 * @since 2025
 */
@SpringBootApplication
@EnableDiscoveryClient // 启用 Nacos 服务发现(注册为 auth-service)
public class AuthApplication {
    public static void main(String[] args) {
        SpringApplication.run(AuthApplication.class, args);
        System.out.println("✅ auth-service 启动成功,监听端口:8081");
    }
}

✅ 使用 @EnableDiscoveryClient 注册到 Nacos,供网关调用:lb://auth-service


2️⃣ config/WebSecurityConfig.java —— Spring Security 配置(全局拦截)

package io.urbane.auth.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;

/**
 * Spring Security 安全配置类
 * 功能:
 *   - 关闭 Session(无状态架构)
 *   - 允许匿名访问 /auth/** 路径(登录、注册接口)
 *   - 对其他所有路径强制认证(JWT 校验由自定义过滤器处理)
 *   - 禁用 CSRF(API 不需要)
 *
 * 注意:实际 JWT 校验在 Gateway 网关的 JwtAuthenticationFilter 中完成,此处仅做路径控制
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())                          // 禁用 CSRF(REST API 不需要)
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)  // 无状态,不创建 Session
            )
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/auth/**").permitAll()           // 允许匿名访问登录/注册/刷新/登出
                .anyRequest().authenticated()                      // 其他所有请求必须认证
            );

        return http.build();
    }
}

🔐 注意:此配置不负责 JWT 校验,只做路径白名单。真正的 Token 验证由 Gateway 网关 JwtAuthenticationFilter 完成。


3️⃣ config/JwtConfig.java —— JWT 配置(密钥、过期时间)

package io.urbane.auth.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * JWT 配置类
 * 功能:
 *   - 从配置文件加载 JWT 秘钥(生产环境建议使用 Vault 或环境变量)
 *   - 定义 Token 默认过期时间(2小时)
 *   - 提供 Bean 方式注入,供其他组件使用
 *
 * 安全建议:
 *   - 秘钥应为 64 字节以上的随机 Base64 编码字符串
 *   - 生产环境不要写死在 yml,应通过环境变量注入:JWT_SECRET=xxxx
 */
@Configuration
public class JwtConfig {

    @Value("${jwt.secret}")
    private String secret; // 如:aGVsbG93b3JsZDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNA==

    @Value("${jwt.expiration-ms:7200000}") // 默认 2 小时 = 7200000 毫秒
    private long expirationMs;

    @Bean
    public String jwtSecret() {
        return secret;
    }

    @Bean
    public long jwtExpirationMs() {
        return expirationMs;
    }
}

✅ 在 application.yml 中配置:

jwt:
  secret: ${JWT_SECRET}  # 生产环境从环境变量注入
  expiration-ms: 7200000 # 2小时

4️⃣ config/RedisConfig.java —— Redis 连接配置(用于 Token 黑名单)

package io.urbane.auth.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;

/**
 * Redis 配置类
 * 功能:
 *   - 配置 Redis 连接工厂(连接 Nacos 中的 Redis)
 *   - 注入 StringRedisTemplate 用于操作 Token 黑名单
 *
 * 用途:
 *   - 存储已注销的 JWT Token:key = "jwt:blacklist:<token>"
 *   - 设置 TTL = 5 分钟,覆盖最长有效窗口
 */
@Configuration
public class RedisConfig {

    @Bean
    public StringRedisTemplate redisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate template = new StringRedisTemplate(factory);
        template.afterPropertiesSet(); // 确保初始化
        return template;
    }
}

✅ 使用 StringRedisTemplate 操作字符串键值对,轻量高效。


5️⃣ controller/AuthController.java —— 认证核心 API

package io.urbane.auth.controller;

import io.urbane.auth.dto.LoginRequest;
import io.urbane.auth.dto.LoginResponse;
import io.urbane.auth.dto.RefreshTokenRequest;
import io.urbane.auth.service.AuthService;
import io.urbane.auth.service.TokenService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

/**
 * 认证控制器(认证相关接口)
 * 路径前缀:/auth
 * 功能:
 *   - /login:用户登录,返回 JWT Token
 *   - /register:用户注册,发送激活邮件
 *   - /logout:用户登出,将 Token 加入黑名单
 *   - /refresh-token:使用旧 Token 换取新 Token
 *
 * 注意:
 *   - 所有接口均无需认证(由 WebSecurityConfig 允许匿名访问)
 *   - 所有输入需校验(@Valid)
 */
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthController {

    private final AuthService authService;
    private final TokenService tokenService;

    /**
     * 用户登录
     * 请求:POST /auth/login
     * 输入:{ username: "zhangsan", password: "123456" }
     * 输出:{ token: "eyJ...", user: { id, username, avatar } }
     */
    @PostMapping("/login")
    public LoginResponse login(@Valid @RequestBody LoginRequest request) {
        return authService.login(request);
    }

    /**
     * 用户注册
     * 请求:POST /auth/register
     * 输入:{ username: "lisi", email: "lisi@example.com", password: "abc123" }
     * 输出:{ success: true }
     */
    @PostMapping("/register")
    public void register(@Valid @RequestBody RegistrationRequest request) {
        authService.register(request);
    }

    /**
     * 用户登出
     * 请求:POST /auth/logout
     * Header:Authorization: Bearer <token>
     * 输出:{ success: true }
     */
    @PostMapping("/logout")
    public void logout(@RequestHeader("Authorization") String authorization) {
        String token = authorization.substring(7); // 移除 "Bearer "
        tokenService.blacklistToken(token);
    }

    /**
     * 刷新 Token(无感续期)
     * 请求:POST /auth/refresh-token
     * 输入:{ token: "旧的JWT" }
     * 输出:{ token: "新的JWT" }
     */
    @PostMapping("/refresh-token")
    public LoginResponse refreshToken(@Valid @RequestBody RefreshTokenRequest request) {
        return authService.refreshToken(request.getToken());
    }
}

✅ 使用 @RequiredArgsConstructor 自动生成构造函数(Lombok),减少样板代码


6️⃣ service/AuthService.java —— 核心业务逻辑

package io.urbane.auth.service;

import io.urbane.auth.dto.LoginRequest;
import io.urbane.auth.dto.LoginResponse;
import io.urbane.auth.dto.RefreshTokenRequest;
import io.urbane.auth.entity.User;
import io.urbane.auth.exception.UserDisabledException;
import io.urbane.auth.repository.UserRepository;
import io.urbane.auth.util.PasswordEncoderUtil;
import io.urbane.auth.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * 认证服务核心实现类
 * 功能:
 *   - 校验用户名密码(BCrypt)
 *   - 检查用户状态(是否冻结)
 *   - 生成 JWT Token(包含 userId、roles)
 *   - 处理 Token 刷新逻辑
 *   - 发布用户注册事件(Kafka)
 *
 * 注意:
 *   - 所有敏感操作(密码比对、Token 生成)在此层完成
 *   - 事务性操作(如注册)使用 @Transactional
 */
@Service
@RequiredArgsConstructor
public class AuthService {

    private final UserRepository userRepository;
    private final JwtUtil jwtUtil;
    private final TokenService tokenService;
    private final EventPublisher eventPublisher; // 假设是 Kafka 事件发布器

    /**
     * 用户登录
     * 步骤:
     *   1. 根据用户名查找用户
     *   2. 检查用户是否存在且未冻结
     *   3. 校验密码(BCrypt)
     *   4. 生成 JWT Token
     *   5. 返回登录响应
     */
    @Transactional(readOnly = true)
    public LoginResponse login(LoginRequest request) {
        User user = userRepository.findByUsername(request.getUsername())
                .orElseThrow(() -> new IllegalArgumentException("用户名或密码错误"));

        if (!user.getStatus().equals(User.Status.ACTIVE)) {
            throw new UserDisabledException("账户已被冻结,请联系客服");
        }

        if (!PasswordEncoderUtil.matches(request.getPassword(), user.getPasswordHash())) {
            throw new IllegalArgumentException("用户名或密码错误");
        }

        String token = jwtUtil.generateToken(user.getId(), user.getRoles());

        return new LoginResponse(
                token,
                new io.urbane.auth.dto.UserBaseInfo(
                        user.getId(),
                        user.getUsername(),
                        user.getNickname(),
                        user.getAvatar()
                )
        );
    }

    /**
     * 用户注册
     * 步骤:
     *   1. 检查用户名/邮箱是否重复
     *   2. 加密密码(BCrypt)
     *   3. 保存用户
     *   4. 发送注册成功事件(异步触发邮件/短信)
     */
    @Transactional
    public void register(io.urbane.auth.dto.RegisterRequest request) {
        if (userRepository.findByUsername(request.getUsername()).isPresent()) {
            throw new IllegalArgumentException("用户名已存在");
        }

        if (userRepository.findByEmail(request.getEmail()).isPresent()) {
            throw new IllegalArgumentException("邮箱已被注册");
        }

        User user = new User();
        user.setUsername(request.getUsername());
        user.setEmail(request.getEmail());
        user.setPasswordHash(PasswordEncoderUtil.encode(request.getPassword()));
        user.setStatus(User.Status.ACTIVE);
        user.setCreatedAt(LocalDateTime.now());
        user.setRoles("USER"); // 默认角色

        userRepository.save(user);

        // 异步发布事件,通知通知服务发送欢迎邮件
        eventPublisher.publish(new UserRegisteredEvent(user.getId(), user.getEmail()));
    }

    /**
     * 刷新 Token(旧 Token 有效,但即将过期)
     * 步骤:
     *   1. 验证旧 Token 是否合法(签名、未过期)
     *   2. 将旧 Token 加入黑名单
     *   3. 生成新 Token
     *   4. 返回新 Token
     */
    @Transactional
    public LoginResponse refreshToken(String oldToken) {
        Long userId = jwtUtil.getUserIdFromToken(oldToken);
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new IllegalArgumentException("用户不存在"));

        // 将旧 Token 加入黑名单
        tokenService.blacklistToken(oldToken);

        // 生成新 Token
        String newToken = jwtUtil.generateToken(userId, user.getRoles());

        return new LoginResponse(
                newToken,
                new io.urbane.auth.dto.UserBaseInfo(
                        user.getId(),
                        user.getUsername(),
                        user.getNickname(),
                        user.getAvatar()
                )
        );
    }
}

关键设计

  • 密码使用 BCryptPasswordEncoder 加密存储,永不存明文
  • 所有异常统一抛出,由全局异常处理器封装为标准 JSON
  • 使用 @Transactional 保证注册原子性

7️⃣ util/JwtUtil.java —— JWT 工具类(核心中的核心)

package io.urbane.auth.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.security.Key;
import java.util.Date;

/**
 * JWT 工具类
 * 功能:
 *   - 生成 JWT Token(包含 userId、roles)
 *   - 解析 Token,提取 userId 和 roles
 *   - 校验 Token 是否过期
 *   - 验证签名有效性
 *
 * 安全要求:
 *   - 使用 RS256 或 HS256 签名算法(生产推荐 RS256)
 *   - 密钥必须保密,不硬编码,使用环境变量注入
 *   - Token 中不存放敏感信息(如密码、手机号)
 */
@Component
public class JwtUtil {

    private final Key signingKey;
    private final long expirationMs;

    public JwtUtil(@Value("${jwt.secret}") String secret, @Value("${jwt.expiration-ms}") long expirationMs) {
        this.signingKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret));
        this.expirationMs = expirationMs;
    }

    /**
     * 生成 JWT Token
     * Payload 示例:
     * {
     *   "sub": "123",
     *   "roles": ["USER"],
     *   "iat": 1712345678,
     *   "exp": 1712352878
     * }
     */
    public String generateToken(Long userId, String roles) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + expirationMs);

        return Jwts.builder()
                .subject(String.valueOf(userId)) // sub = subject
                .claim("roles", roles)           // 自定义声明:角色列表
                .issuedAt(now)
                .expiration(expiryDate)
                .signWith(signingKey, SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 从 Token 中提取用户 ID
     */
    public Long getUserIdFromToken(String token) {
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(signingKey)
                .build()
                .parseClaimsJws(token)
                .getBody();

        String subject = claims.getSubject();
        if (subject == null) {
            throw new IllegalArgumentException("Token 中未包含用户ID");
        }
        return Long.parseLong(subject);
    }

    /**
     * 从 Token 中提取角色
     */
    public String getRolesFromToken(String token) {
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(signingKey)
                .build()
                .parseClaimsJws(token)
                .getBody();

        Object rolesObj = claims.get("roles");
        return rolesObj != null ? rolesObj.toString() : "";
    }

    /**
     * 校验 Token 是否过期
     */
    public boolean isTokenExpired(String token) {
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(signingKey)
                .build()
                .parseClaimsJws(token)
                .getBody();

        Date expiration = claims.getExpiration();
        return expiration.before(new Date());
    }
}

重要

  • 使用 HS256 是为了简化部署(无需证书)
  • 生产环境建议改用 RS256 + 公私钥对,安全性更高
  • 永远不要在 Token 中存储密码、手机号、身份证

8️⃣ exception/AuthException.java —— 自定义异常体系

package io.urbane.auth.exception;

import org.springframework.http.HttpStatus;

/**
 * 认证异常基类
 * 所有认证相关异常都继承此类,便于全局异常处理器统一处理
 */
public class AuthException extends RuntimeException {

    protected final HttpStatus status;

    public AuthException(HttpStatus status, String message) {
        super(message);
        this.status = status;
    }

    public HttpStatus getStatus() {
        return status;
    }
}

// 子类示例:

/**
 * 用户被禁用(非删除)
 */
public class UserDisabledException extends AuthException {
    public UserDisabledException(String message) {
        super(HttpStatus.FORBIDDEN, message);
    }
}

/**
 * Token 无效(签名错误、过期、被吊销)
 */
public class InvalidTokenException extends AuthException {
    public InvalidTokenException(String message) {
        super(HttpStatus.UNAUTHORIZED, message);
    }
}

/**
 * 用户不存在
 */
public class UserNotFoundException extends AuthException {
    public UserNotFoundException(String message) {
        super(HttpStatus.NOT_FOUND, message);
    }
}

✅ 全局异常处理器会根据 status 返回对应 HTTP 状态码,前端统一处理


9️⃣ aspect/AuthLogAspect.java —— 操作日志切面

package io.urbane.auth.aspect;

import io.urbane.auth.util.UserContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * 认证操作日志切面
 * 功能:
 *   - 拦截登录、登出、刷新 Token 操作
 *   - 记录操作类型、用户ID、IP地址、设备信息
 *   - 写入审计日志,便于追溯
 *
 * 注意:
 *   - 必须配合 MDC(Mapped Diagnostic Context)使用
 *   - 日志中自动携带 traceId、userId
 */
@Aspect
@Component
@Slf4j
public class AuthLogAspect {

    @Around("execution(* io.urbane.auth.service.AuthService.login(..)) || " +
            "execution(* io.urbane.auth.service.AuthService.logout(..)) || " +
            "execution(* io.urbane.auth.service.AuthService.refreshToken(..))")
    public Object logAuthOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String ip = getCurrentIp(); // 从 HttpServletRequest 获取(需注入)

        // 从 ThreadLocal 获取当前用户ID(由过滤器设置)
        Long userId = UserContext.getUser();

        log.info("【认证操作】{} | userId={} | ip={}", methodName, userId, ip);

        try {
            Object result = joinPoint.proceed();
            log.info("【认证操作成功】{} | userId={}", methodName, userId);
            return result;
        } catch (Exception e) {
            log.warn("【认证操作失败】{} | userId={} | error={}", methodName, userId, e.getMessage());
            throw e;
        }
    }

    private String getCurrentIp() {
        // 实际项目中可通过 RequestContextHolder 获取 HttpServletRequest
        // 此处简化,仅作示意
        return "127.0.0.1";
    }
}

✅ 日志输出示例:

[traceId=a1b2c3, userId=123] 【认证操作】login | userId=123 | ip=192.168.1.10
[traceId=a1b2c3, userId=123] 【认证操作成功】login | userId=123

🔟 constant/JwtClaimKeys.java —— JWT Claim 常量(防魔法字符串)

package io.urbane.auth.constant;

/**
 * JWT Claim 键名常量
 * 功能:
 *   - 避免在代码中直接写 "sub"、"roles" 等魔法字符串
 *   - 提升可读性和可维护性
 *   - 便于统一修改
 */
public interface JwtClaimKeys {
    String SUBJECT = "sub";      // 用户ID
    String ROLES = "roles";      // 角色列表
    String ISSUER = "iss";       // 签发者
    String EXPIRATION = "exp";   // 过期时间
    String ISSUED_AT = "iat";    // 签发时间
}

✅ 使用方式:

.claim(JwtClaimKeys.SUBJECT, userId)

✅ 四、总结:为什么这套结构是工业级标准?

特性说明
职责分离每个包各司其职,不交叉
安全合规密码加密、Token 无敏感数据、黑名单机制
可测试所有 Service 可独立单元测试,Mock Repository
可观测日志带 traceId/userId,接入 ELK/Sentry
可扩展支持微信登录、OAuth2、多租户只需加模块
一致性所有异常、DTO、工具命名风格统一
符合 DDD模块划分贴近领域模型(认证域)

🚀 最终建议:立即行动清单

步骤操作
✅ 1按上述结构创建 auth-service/src/main/java/io/urbane/auth/ 下所有包
✅ 2复制每个 .java 文件内容,保留中文注释
✅ 3pom.xml 中引入 Lombok、JWT、Redis、Nacos 依赖
✅ 4application.yml 中配置 jwt.secretnacos.server-addr
✅ 5创建数据库表 users(id, username, password_hash, email, status, created_at)
✅ 6启动服务,测试 /auth/login/auth/register/auth/logout
✅ 7在 GitLab CI 中加入 mvn testmvn package 流程

📦 Bonus:我为你准备了完整 ZIP 模板包

如果你希望我为你提供:

  • 完整的 auth-service 项目 ZIP(含所有 Java 文件、配置、SQL)
  • schema.sql 用户表建表语句
  • Postman Collection(登录/注册/登出测试用例)
  • Dockerfile(基于 OpenJDK 17)
  • Kubernetes Deployment + Service YAML
  • GitLab CI Pipeline(自动构建+部署)

👉 请回复:
“请给我完整的 auth-service 项目模板包!”

我会立刻发送你一份开箱即用的企业级认证服务完整工程,包含所有上述规范的实现,你只需 git clone,当天就能上线 💪

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙茶清欢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值