184 lines
5.9 KiB
Markdown
184 lines
5.9 KiB
Markdown
# 登录日志 401 错误代码检查报告
|
||
|
||
## 检查时间
|
||
2025-01-30
|
||
|
||
## 检查范围
|
||
- 前端 API 调用
|
||
- 前端页面组件
|
||
- 后端控制器
|
||
- 权限检查逻辑
|
||
- Token 处理
|
||
|
||
## 检查结果
|
||
|
||
### ✅ 前端代码检查
|
||
|
||
#### 1. API 调用对比
|
||
**文件:`study-ui/src/api/monitor/logininfor.js` vs `operlog.js`**
|
||
|
||
| 项目 | logininfor | operlog | 状态 |
|
||
|------|-----------|---------|------|
|
||
| URL 路径 | `/monitor/logininfor/list` | `/monitor/operlog/list` | ✅ 一致 |
|
||
| 请求方法 | `get` | `get` | ✅ 一致 |
|
||
| 参数处理 | `params: query` | `params: query` | ✅ 一致 |
|
||
| 导入方式 | `import request from '@/utils/request'` | `import request from '@/utils/request'` | ✅ 一致 |
|
||
|
||
**结论:** 前端 API 调用代码完全一致,无差异。
|
||
|
||
#### 2. 页面组件对比
|
||
**文件:`study-ui/src/views/monitor/logininfor/index.vue` vs `operlog/index.vue`**
|
||
|
||
| 项目 | logininfor | operlog | 状态 |
|
||
|------|-----------|---------|------|
|
||
| 生命周期 | `created()` 中调用 `getList()` | `created()` 中调用 `getList()` | ✅ 一致 |
|
||
| 错误处理 | 无 `.catch()` | 无 `.catch()` | ✅ 一致 |
|
||
| 列表查询方法 | `list(this.addDateRange(...))` | `list(this.addDateRange(...))` | ✅ 一致 |
|
||
|
||
**结论:** 页面组件实现完全一致,无差异。
|
||
|
||
#### 3. 请求拦截器检查
|
||
**文件:`study-ui/src/utils/request.js`**
|
||
|
||
- ✅ Token 添加逻辑正常:`config.headers['Authorization'] = 'Bearer ' + getToken()`
|
||
- ✅ GET 请求参数处理正常
|
||
- ✅ 响应拦截器 401 处理正常
|
||
|
||
**结论:** 请求拦截器配置正常。
|
||
|
||
### ✅ 后端代码检查
|
||
|
||
#### 1. 控制器对比
|
||
**文件:**
|
||
- `ry-study-admin/.../SysLogininforController.java`
|
||
- `ry-study-admin/.../SysOperlogController.java`
|
||
|
||
| 项目 | SysLogininforController | SysOperlogController | 状态 |
|
||
|------|------------------------|---------------------|------|
|
||
| 注解 | `@RestController` | `@RestController` | ✅ 一致 |
|
||
| 路径映射 | `@RequestMapping("/monitor/logininfor")` | `@RequestMapping("/monitor/operlog")` | ✅ 一致 |
|
||
| 权限注解 | `@PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")` | `@PreAuthorize("@ss.hasPermi('monitor:operlog:list')")` | ✅ 一致 |
|
||
| 方法实现 | `startPage()` + `selectLogininforList()` | `startPage()` + `selectOperLogList()` | ✅ 一致 |
|
||
| 返回类型 | `TableDataInfo` | `TableDataInfo` | ✅ 一致 |
|
||
|
||
**结论:** 控制器代码完全一致,无差异。
|
||
|
||
#### 2. 权限检查逻辑
|
||
**文件:`ry-study-framework/.../PermissionService.java`**
|
||
|
||
```java
|
||
public boolean hasPermi(String permission) {
|
||
if (StringUtils.isEmpty(permission)) {
|
||
return false;
|
||
}
|
||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) {
|
||
return false;
|
||
}
|
||
PermissionContextHolder.setContext(permission);
|
||
return hasPermissions(loginUser.getPermissions(), permission);
|
||
}
|
||
|
||
private boolean hasPermissions(Set<String> permissions, String permission) {
|
||
return permissions.contains(Constants.ALL_PERMISSION) ||
|
||
permissions.contains(StringUtils.trim(permission));
|
||
}
|
||
```
|
||
|
||
**检查点:**
|
||
- ✅ 权限检查逻辑正常
|
||
- ✅ 支持通配符权限 `*:*:*`
|
||
- ✅ 权限字符串会进行 trim 处理
|
||
|
||
**结论:** 权限检查逻辑正常,无问题。
|
||
|
||
#### 3. Token 处理
|
||
**文件:`ry-study-framework/.../JwtAuthenticationTokenFilter.java`**
|
||
|
||
- ✅ Token 提取逻辑正常
|
||
- ✅ 用户信息从 Redis 获取
|
||
- ✅ 权限信息从 `LoginUser.getPermissions()` 获取
|
||
|
||
**结论:** Token 处理逻辑正常。
|
||
|
||
## 🔍 问题分析
|
||
|
||
### 代码层面
|
||
**所有代码检查均正常,无差异。**
|
||
|
||
### 可能的问题原因
|
||
|
||
#### 1. 数据库权限配置问题 ⚠️(最可能)
|
||
- **现象:** 菜单配置显示"正常",但用户实际没有该权限
|
||
- **原因:**
|
||
- `sys_role_menu` 表中缺少角色与 `monitor:logininfor:list` 菜单的关联
|
||
- 或者用户角色关联不正确
|
||
- **验证方法:** 执行 `check_permissions.sql` 中的查询
|
||
|
||
#### 2. Redis 缓存问题 ⚠️
|
||
- **现象:** 数据库权限已更新,但 Redis 中仍是旧数据
|
||
- **原因:**
|
||
- 用户登录后,权限信息缓存在 Redis 中
|
||
- 如果数据库权限更新,但用户未重新登录,Redis 中仍是旧权限
|
||
- **解决方法:**
|
||
1. 清除 Redis 缓存:`KEYS login_tokens:*` 然后删除
|
||
2. 或者重启 Redis
|
||
3. 重新登录系统
|
||
|
||
#### 3. 权限字符串差异 ⚠️
|
||
- **现象:** 权限字符串可能有细微差异(空格、大小写等)
|
||
- **验证方法:** 检查数据库中 `sys_menu.perms` 字段的值
|
||
|
||
## 📋 建议的排查步骤
|
||
|
||
### 步骤 1:检查数据库权限配置
|
||
```sql
|
||
-- 检查用户是否有 monitor:logininfor:list 权限
|
||
SELECT
|
||
u.user_name,
|
||
r.role_name,
|
||
m.perms
|
||
FROM sys_user u
|
||
LEFT JOIN sys_user_role ur ON u.user_id = ur.user_id
|
||
LEFT JOIN sys_role r ON ur.role_id = r.role_id
|
||
LEFT JOIN sys_role_menu rm ON r.role_id = rm.role_id
|
||
LEFT JOIN sys_menu m ON rm.menu_id = m.menu_id
|
||
WHERE u.user_name = 'admin' -- 替换为你的用户名
|
||
AND m.perms IN ('monitor:logininfor:list', 'monitor:operlog:list')
|
||
ORDER BY m.perms;
|
||
```
|
||
|
||
### 步骤 2:如果权限缺失,执行修复
|
||
```sql
|
||
-- 参考 fix_logininfor_permission.sql 文件
|
||
```
|
||
|
||
### 步骤 3:清除 Redis 缓存
|
||
```bash
|
||
# 在 Redis 中执行
|
||
KEYS login_tokens:*
|
||
# 删除所有匹配的 key
|
||
# 或者
|
||
FLUSHDB # 仅开发环境
|
||
```
|
||
|
||
### 步骤 4:重新登录并测试
|
||
1. 清除浏览器 Cookie
|
||
2. 重新登录系统
|
||
3. 测试登录日志页面
|
||
|
||
## 🎯 结论
|
||
|
||
**代码检查结果:所有代码正常,无差异。**
|
||
|
||
**问题定位:** 问题不在代码层面,而是在数据层面:
|
||
1. 数据库权限配置可能不完整
|
||
2. Redis 缓存可能过期
|
||
|
||
**建议操作:**
|
||
1. 执行 `check_permissions.sql` 检查权限配置
|
||
2. 如果权限缺失,执行 `fix_logininfor_permission.sql` 修复
|
||
3. 清除 Redis 缓存
|
||
4. 重新登录测试
|
||
|