# 认证功能生命周期详解 ## 1. 控制器层 (Controller) ### 1.1 用户注册接口 **接口定义**:`UserAuthController.register()` ```java @PostMapping("/register") public ApiResult register(@RequestBody @Validated UserRegisterRequest request) { return userAuthService.register(request); } ``` **功能职责**: - 接收用户注册请求 - 参数校验(通过`@Validated`注解) - 调用服务层处理注册逻辑 - 返回统一格式的注册结果 **请求参数(UserRegisterRequest)**: ```json { "username": "enterprise_user1", "password": "Password@123", "confirmPassword": "Password@123", "mobile": "13812345678", "email": "test@example.com", "userType": "ENTERPRISE", "enterpriseInfo": { "enterpriseName": "测试企业有限公司", "creditCode": "91110000ABCDEFG123", "legalPerson": "张三", "contactPhone": "13812345678" } } ``` **响应结果(UserRegisterResponse)**: ```json { "code": 200, "message": "注册成功", "data": { "userId": "1234567890", "username": "enterprise_user1", "userType": "ENTERPRISE", "registrationTime": "2023-08-15T10:30:45Z" } } ``` ### 1.2 用户登录接口 **接口定义**:`UserAuthController.login()` ```java @PostMapping("/login") public ApiResult login(@RequestBody @Validated LoginRequest request) { return userAuthService.login(request); } ``` **功能职责**: - 接收用户登录请求 - 参数校验 - 调用服务层处理登录逻辑 - 返回统一格式的登录结果(包含JWT令牌) **请求参数(LoginRequest)**: ```json { "username": "enterprise_user1", "password": "Password@123" } ``` **响应结果(LoginResponse)**: ```json { "code": 200, "message": "登录成功", "data": { "userId": "1234567890", "username": "enterprise_user1", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expiresIn": 3600 } } ``` ### 1.3 刷新令牌接口 **接口定义**:`UserAuthController.refreshToken()` ```java @PostMapping("/refresh-token") public ApiResult refreshToken(@RequestBody @Validated RefreshTokenRequest request) { return userAuthService.refreshToken(request); } ``` ### 1.4 登出接口 **接口定义**:`UserAuthController.logout()` ```java @PostMapping("/logout") public ApiResult logout(@RequestHeader("Authorization") String token) { return userAuthService.logout(token); } ``` ## 2. 服务层 (Service) ### 2.1 用户认证服务 **主要实现类**:`UserAuthServiceImpl` #### 2.1.1 注册业务流程 `register()` ```java @Override @Transactional(rollbackFor = Exception.class) public ApiResult register(UserRegisterRequest request) { // 1. 检查用户名是否已存在 if (userMapper.existsByUsername(request.getUsername())) { return ApiResult.failed("用户名已存在"); } // 2. 检查手机号是否已注册 if (userMapper.existsByMobile(request.getMobile())) { return ApiResult.failed("手机号已注册"); } // 3. 密码加密 String encryptedPassword = passwordEncoder.encode(request.getPassword()); // 4. 构建用户对象 User user = new User(); user.setUserId(IdGenerator.generateId()); user.setUsername(request.getUsername()); user.setPassword(encryptedPassword); user.setMobile(request.getMobile()); user.setEmail(request.getEmail()); user.setUserType(request.getUserType()); user.setStatus(UserStatus.NORMAL); user.setCreateTime(new Date()); // 5. 保存用户信息 userMapper.insert(user); // 6. 企业用户需保存企业信息 if (UserType.ENTERPRISE.equals(request.getUserType())) { EnterpriseInfo enterpriseInfo = request.getEnterpriseInfo(); enterpriseInfo.setUserId(user.getUserId()); enterpriseInfo.setVerifyStatus(VerifyStatus.UNVERIFIED); enterpriseInfoMapper.insert(enterpriseInfo); } // 7. 分配默认角色权限 roleService.assignDefaultRole(user.getUserId(), user.getUserType()); // 8. 发送注册成功通知 notificationService.sendRegistrationNotification(user); // 9. 构建返回结果 UserRegisterResponse response = new UserRegisterResponse(); response.setUserId(user.getUserId()); response.setUsername(user.getUsername()); response.setUserType(user.getUserType()); response.setRegistrationTime(user.getCreateTime()); return ApiResult.success("注册成功", response); } ``` **处理逻辑**: 1. 用户名和手机号唯一性校验 2. 密码加密存储 3. 保存用户基本信息 4. 保存企业附加信息(如适用) 5. 分配默认角色和权限 6. 发送注册成功通知 7. 构建返回结果 #### 2.1.2 登录业务流程 `login()` ```java @Override public ApiResult login(LoginRequest request) { // 1. 根据用户名查询用户 User user = userMapper.selectByUsername(request.getUsername()); if (user == null) { return ApiResult.failed("用户名或密码错误"); } // 2. 检查用户状态 if (!UserStatus.NORMAL.equals(user.getStatus())) { return ApiResult.failed("账号已被禁用,请联系管理员"); } // 3. 验证密码 if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) { // 4. 记录登录失败次数 loginFailService.recordFailedLogin(user.getUserId()); return ApiResult.failed("用户名或密码错误"); } // 5. 清除登录失败记录 loginFailService.clearFailedLogin(user.getUserId()); // 6. 生成JWT令牌 String token = jwtTokenProvider.generateToken(user); String refreshToken = jwtTokenProvider.generateRefreshToken(user); // 7. 保存令牌信息 tokenService.saveToken(user.getUserId(), token, refreshToken); // 8. 记录登录日志 auditLogService.logLogin(user.getUserId(), request.getLoginIp(), LoginResult.SUCCESS); // 9. 构建返回结果 LoginResponse response = new LoginResponse(); response.setUserId(user.getUserId()); response.setUsername(user.getUsername()); response.setToken(token); response.setRefreshToken(refreshToken); response.setExpiresIn(jwtTokenProvider.getExpirationTime()); return ApiResult.success("登录成功", response); } ``` **处理逻辑**: 1. 验证用户存在性 2. 检查用户状态(是否被禁用) 3. 验证密码正确性 4. 处理登录失败记录 5. 生成JWT令牌和刷新令牌 6. 保存令牌信息到缓存 7. 记录登录日志 8. 构建返回结果 ### 2.2 JWT令牌服务 **主要实现类**:`JwtTokenProviderImpl` #### 2.2.1 生成令牌 `generateToken()` ```java @Override public String generateToken(User user) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + tokenExpirationMs); Map claims = new HashMap<>(); claims.put("userId", user.getUserId()); claims.put("username", user.getUsername()); claims.put("userType", user.getUserType()); return Jwts.builder() .setClaims(claims) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS256, jwtSecret) .compact(); } ``` #### 2.2.2 验证令牌 `validateToken()` ```java @Override public boolean validateToken(String token) { try { Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token); return true; } catch (SignatureException ex) { log.error("Invalid JWT signature"); } catch (MalformedJwtException ex) { log.error("Invalid JWT token"); } catch (ExpiredJwtException ex) { log.error("Expired JWT token"); } catch (UnsupportedJwtException ex) { log.error("Unsupported JWT token"); } catch (IllegalArgumentException ex) { log.error("JWT claims string is empty"); } return false; } ``` ## 3. 数据访问层 (Mapper/Repository) ### 3.1 用户数据访问 **主要实现类**:`UserMapper` ```java @Mapper public interface UserMapper { /** * 插入用户 */ int insert(User user); /** * 根据用户名查询 */ User selectByUsername(String username); /** * 检查用户名是否存在 */ boolean existsByUsername(String username); /** * 检查手机号是否存在 */ boolean existsByMobile(String mobile); /** * 根据ID查询 */ User selectById(String userId); /** * 更新用户信息 */ int update(User user); } ``` ### 3.2 企业信息数据访问 **主要实现类**:`EnterpriseInfoMapper` ```java @Mapper public interface EnterpriseInfoMapper { /** * 插入企业信息 */ int insert(EnterpriseInfo enterpriseInfo); /** * 根据用户ID查询 */ EnterpriseInfo selectByUserId(String userId); /** * 根据统一社会信用代码查询 */ EnterpriseInfo selectByCreditCode(String creditCode); /** * 更新企业信息 */ int update(EnterpriseInfo enterpriseInfo); } ``` ## 4. 安全拦截层 ### 4.1 JWT认证过滤器 **主要实现类**:`JwtAuthenticationFilter` ```java @Component @RequiredArgsConstructor public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtTokenProvider jwtTokenProvider; private final UserDetailsService userDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { try { // 1. 从请求中获取JWT令牌 String jwt = getJwtFromRequest(request); // 2. 验证令牌有效性 if (StringUtils.hasText(jwt) && jwtTokenProvider.validateToken(jwt)) { // 3. 从令牌中获取用户ID String userId = jwtTokenProvider.getUserIdFromToken(jwt); // 4. 加载用户详情 UserDetails userDetails = userDetailsService.loadUserById(userId); // 5. 创建认证对象 UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); // 6. 设置认证上下文 SecurityContextHolder.getContext().setAuthentication(authentication); } } catch (Exception ex) { logger.error("Could not set user authentication in security context", ex); } // 7. 继续过滤器链 filterChain.doFilter(request, response); } private String getJwtFromRequest(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } } ``` **处理逻辑**: 1. 从HTTP请求头中提取JWT令牌 2. 验证令牌的有效性 3. 从令牌中解析用户信息 4. 加载用户详情和权限 5. 创建认证对象 6. 设置Spring Security上下文 7. 继续过滤器链处理 ## 5. 实体类层 (Entity/Model) ### 5.1 用户实体 ```java @Data @Table(name = "t_user") public class User implements Serializable { @Id private String userId; private String username; private String password; private String mobile; private String email; @Enumerated(EnumType.STRING) private UserType userType; @Enumerated(EnumType.STRING) private UserStatus status; private Date createTime; private Date updateTime; } ``` ### 5.2 企业信息实体 ```java @Data @Table(name = "t_enterprise_info") public class EnterpriseInfo implements Serializable { @Id private String id; private String userId; private String enterpriseName; private String creditCode; private String legalPerson; private String contactPhone; @Enumerated(EnumType.STRING) private VerifyStatus verifyStatus; private Date createTime; private Date updateTime; } ``` ## 6. 异常处理 ### 6.1 全局异常处理器 **主要实现类**:`GlobalExceptionHandler` ```java @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * 处理参数验证异常 */ @ExceptionHandler(MethodArgumentNotValidException.class) public ApiResult handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) { BindingResult bindingResult = ex.getBindingResult(); StringBuilder sb = new StringBuilder("参数校验失败:"); for (FieldError fieldError : bindingResult.getFieldErrors()) { sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", "); } String msg = sb.toString(); log.warn(msg); return ApiResult.validateFailed(msg); } /** * 处理业务异常 */ @ExceptionHandler(BusinessException.class) public ApiResult handleBusinessException(BusinessException ex) { log.error("业务异常", ex); return ApiResult.failed(ex.getCode(), ex.getMessage()); } /** * 处理未授权异常 */ @ExceptionHandler(AccessDeniedException.class) public ApiResult handleAccessDeniedException(AccessDeniedException ex) { log.error("权限不足", ex); return ApiResult.forbidden("没有权限执行此操作"); } /** * 处理其他未知异常 */ @ExceptionHandler(Exception.class) public ApiResult handleException(Exception ex) { log.error("系统异常", ex); return ApiResult.failed("服务器内部错误,请稍后重试"); } } ``` ## 7. 缓存层 ### 7.1 令牌缓存服务 **主要实现类**:`TokenServiceImpl` ```java @Service @RequiredArgsConstructor public class TokenServiceImpl implements TokenService { private final RedisTemplate redisTemplate; private final JwtTokenProvider jwtTokenProvider; private static final String TOKEN_KEY_PREFIX = "auth:token:"; private static final String REFRESH_TOKEN_KEY_PREFIX = "auth:refresh_token:"; @Override public void saveToken(String userId, String token, String refreshToken) { // 保存访问令牌,过期时间与JWT令牌一致 String tokenKey = TOKEN_KEY_PREFIX + userId; redisTemplate.opsForValue().set(tokenKey, token, jwtTokenProvider.getExpirationTime(), TimeUnit.MILLISECONDS); // 保存刷新令牌,过期时间更长 String refreshTokenKey = REFRESH_TOKEN_KEY_PREFIX + userId; redisTemplate.opsForValue().set(refreshTokenKey, refreshToken, jwtTokenProvider.getRefreshExpirationTime(), TimeUnit.MILLISECONDS); } @Override public String getToken(String userId) { String key = TOKEN_KEY_PREFIX + userId; Object token = redisTemplate.opsForValue().get(key); return token != null ? token.toString() : null; } @Override public String getRefreshToken(String userId) { String key = REFRESH_TOKEN_KEY_PREFIX + userId; Object refreshToken = redisTemplate.opsForValue().get(key); return refreshToken != null ? refreshToken.toString() : null; } @Override public void removeToken(String userId) { String tokenKey = TOKEN_KEY_PREFIX + userId; String refreshTokenKey = REFRESH_TOKEN_KEY_PREFIX + userId; redisTemplate.delete(tokenKey); redisTemplate.delete(refreshTokenKey); } } ``` ## 8. 日志审计 ### 8.1 登录日志服务 **主要实现类**:`AuditLogServiceImpl` ```java @Service @RequiredArgsConstructor public class AuditLogServiceImpl implements AuditLogService { private final AuditLogMapper auditLogMapper; @Override public void logLogin(String userId, String ip, LoginResult result) { AuditLog log = new AuditLog(); log.setUserId(userId); log.setOperationType(OperationType.LOGIN); log.setOperationResult(result.toString()); log.setIp(ip); log.setCreateTime(new Date()); auditLogMapper.insert(log); } @Override public void logLogout(String userId, String ip) { AuditLog log = new AuditLog(); log.setUserId(userId); log.setOperationType(OperationType.LOGOUT); log.setOperationResult(LoginResult.SUCCESS.toString()); log.setIp(ip); log.setCreateTime(new Date()); auditLogMapper.insert(log); } } ``` ## 9. 完整认证流程时序 ``` ┌──────────┐ ┌───────────────┐ ┌─────────────┐ ┌──────────┐ ┌─────────┐ │ 客户端 │ │ 控制器层 │ │ 服务层 │ │ 数据访问层│ │ 缓存层 │ └────┬─────┘ └───────┬───────┘ └──────┬──────┘ └────┬─────┘ └────┬────┘ │ │ │ │ │ │ 1. 登录请求 │ │ │ │ │ ───────────────────────> │ │ │ │ │ │ │ │ │ │ 2. 调用登录服务 │ │ │ │ │ ─────────────────────────> │ │ │ │ │ │ │ │ │ │ 3. 查询用户 │ │ │ │ │ ─────────────────────> │ │ │ │ │ │ │ │ │ 4. 返回用户数据 │ │ │ │ │ <───────────────────── │ │ │ │ │ │ │ │ │ 5. 生成令牌 │ │ │ │ │ ─────────────────────────────────────────> │ │ │ │ │ │ │ │ │ 6. 令牌缓存完成 │ │ │ │ │ <───────────────────────────────────────── │ │ │ │ │ │ │ │ 7. 返回登录结果 │ │ │ │ │ <───────────────────────── │ │ │ │ │ │ │ │ 8. 返回令牌 │ │ │ │ │ <─────────────────────── │ │ │ │ │ │ │ │ │ 9. 后续请求(带令牌) │ │ │ │ │ ───────────────────────> │ │ │ │ │ │ │ │ │ │ 10.令牌校验 │ │ │ │ │ ─────────────────────────> │ │ │ │ │ │ │ │ │ 11.校验通过 │ │ │ │ │ <───────────────────────── │ │ │ │ │ │ │ │ 12.返回请求结果 │ │ │ │ │ <─────────────────────── │ │ │ │ │ │ │ │ ```