# Xiaozhi ESP32 Server - 用户未登录导致数据库插入失败故障分析 ## 故障现象 - **错误信息**: `java.sql.SQLIntegrityConstraintViolationException: Column 'userId' cannot be null` - **发生时间**: 2025-07-08 09:44:58 - 09:50:33 - **影响接口**: `/api/config/add` - **错误频率**: 多次重复出现 ## 问题分析 ### 1. 根本原因 用户在未登录状态下访问了需要认证的接口 `/api/config/add`,导致: - `CmsUtils.getUserId()` 返回 null - 数据库插入时 userId 字段为 null - 违反数据库 NOT NULL 约束 ### 2. 认证机制分析 #### 当前认证流程: 1. `AuthenticationInterceptor` 拦截所有请求 2. 检查会话中是否有用户信息 3. 如果没有,尝试从 Cookie 中获取用户名并自动登录 4. 如果都失败,返回 401 未授权错误 #### 配置问题: ```java // WebMvcConfig.java registry.addInterceptor(authenticationInterceptor) .addPathPatterns("/**") .excludePathPatterns( "/api/user/login", "/api/user/register", "/api/device/ota", "/audio/**", "/uploads/**", "/avatar/**", "/ws/**" ); ``` `/api/config/**` 路径需要认证,但拦截器似乎没有正确拦截。 ### 3. 可能的原因 1. **Cookie 认证失败** - Cookie 中的用户名存在,但数据库中找不到对应用户 - Cookie 认证成功,但没有正确设置 userId 2. **请求处理顺序问题** - 拦截器执行顺序可能有问题 - `RequestContextHolder` 的属性设置时机不对 3. **前端问题** - 前端可能在用户未登录时错误地调用了接口 - 前端可能缓存了过期的认证信息 ## 解决方案 ### 1. 短期修复(已实施) 在 `ConfigController` 中添加显式的登录检查: ```java @PostMapping("/add") @ResponseBody public AjaxResult add(SysConfig config) { try { // 获取当前用户ID Integer userId = CmsUtils.getUserId(); // 检查用户是否已登录 if (userId == null) { return AjaxResult.error(HttpStatus.FORBIDDEN, "用户未登录,请先登录"); } config.setUserId(userId); configService.add(config); return AjaxResult.success(); } catch (Exception e) { logger.error(e.getMessage(), e); return AjaxResult.error(); } } ``` ### 2. 长期改进建议 #### 2.1 修复认证拦截器 确保拦截器在用户未登录时正确返回 401 错误,而不是让请求继续执行。 #### 2.2 统一认证检查 创建一个基础控制器方法,统一处理用户认证检查: ```java protected Integer requireUserId() { Integer userId = CmsUtils.getUserId(); if (userId == null) { throw new UnauthorizedException("用户未登录"); } return userId; } ``` #### 2.3 全局异常处理 在 `GlobalExceptionHandler` 中添加对 `UnauthorizedException` 的处理。 #### 2.4 前端改进 - 在 API 调用前检查用户登录状态 - 收到 401 错误时自动跳转到登录页面 - 清理过期的认证信息 ### 3. 需要检查的其他接口 以下接口也使用了 `CmsUtils.getUserId()`,需要添加类似的检查: - `/api/role/add` - `/api/role/update` - `/api/role/query` - `/api/device/add` - `/api/device/update` - `/api/device/query` - `/api/agent/add` - `/api/template/add` - `/api/template/update` - `/api/template/query` ## 监控建议 1. **添加日志监控** - 记录所有认证失败的请求 - 监控 userId 为 null 的情况 2. **添加告警** - 当出现大量认证失败时发送告警 - 监控数据库约束违反错误 3. **定期审查** - 审查所有需要用户认证的接口 - 确保认证机制正常工作 ## 总结 这是一个典型的认证机制失效导致的数据完整性问题。虽然已经通过在控制器层添加检查来临时解决,但根本问题是认证拦截器没有正确工作。建议尽快修复拦截器,并在所有需要用户认证的接口中添加统一的认证检查机制。