4.0 KiB
4.0 KiB
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. 认证机制分析
当前认证流程:
AuthenticationInterceptor拦截所有请求- 检查会话中是否有用户信息
- 如果没有,尝试从 Cookie 中获取用户名并自动登录
- 如果都失败,返回 401 未授权错误
配置问题:
// WebMvcConfig.java
registry.addInterceptor(authenticationInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(
"/api/user/login",
"/api/user/register",
"/api/device/ota",
"/audio/**",
"/uploads/**",
"/avatar/**",
"/ws/**"
);
/api/config/** 路径需要认证,但拦截器似乎没有正确拦截。
3. 可能的原因
-
Cookie 认证失败
- Cookie 中的用户名存在,但数据库中找不到对应用户
- Cookie 认证成功,但没有正确设置 userId
-
请求处理顺序问题
- 拦截器执行顺序可能有问题
RequestContextHolder的属性设置时机不对
-
前端问题
- 前端可能在用户未登录时错误地调用了接口
- 前端可能缓存了过期的认证信息
解决方案
1. 短期修复(已实施)
在 ConfigController 中添加显式的登录检查:
@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 统一认证检查
创建一个基础控制器方法,统一处理用户认证检查:
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
监控建议
-
添加日志监控
- 记录所有认证失败的请求
- 监控 userId 为 null 的情况
-
添加告警
- 当出现大量认证失败时发送告警
- 监控数据库约束违反错误
-
定期审查
- 审查所有需要用户认证的接口
- 确保认证机制正常工作
总结
这是一个典型的认证机制失效导致的数据完整性问题。虽然已经通过在控制器层添加检查来临时解决,但根本问题是认证拦截器没有正确工作。建议尽快修复拦截器,并在所有需要用户认证的接口中添加统一的认证检查机制。