coder-common-thin-backend/api/system/登录日志API.md
Leo aea2b1fbd7 docs: 新增完整的API接口文档
- 添加认证相关API文档(登录认证、验证码)
- 添加权限管理API文档(菜单管理、角色管理)
- 添加系统管理API文档(图片管理、文件管理、登录日志)
- 添加用户管理API文档
- 完善项目API文档结构,提升开发体验
2025-07-06 00:54:47 +08:00

1017 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 登录日志API
## 概述
登录日志模块用于记录和管理系统用户的登录行为,包括登录成功、登录失败、退出登录等操作的详细记录。提供日志查询、统计分析和安全监控功能,是系统安全审计的重要组成部分。
## 权限说明
登录日志接口需要相应的权限才能访问:
| 操作 | 权限码 | 说明 |
|------|--------|------|
| 查询登录日志 | `system:loginlog:list` | 查看登录日志权限 |
| 删除登录日志 | `system:loginlog:remove` | 删除登录日志权限 |
| 导出登录日志 | `system:loginlog:export` | 导出登录日志权限 |
## 接口列表
### 1. 分页查询登录日志
**接口地址**: `GET /coder/sysLoginLog/listPage`
**接口描述**: 分页查询系统登录日志列表
**是否需要认证**: 是
**权限要求**: `system:loginlog:list`
**请求头**:
```
Authorization: Bearer your-token-value
```
**请求参数**:
| 参数名 | 类型 | 必填 | 说明 | 示例 |
|--------|------|------|------|------|
| pageNo | Integer | 否 | 页码 | 1 |
| pageSize | Integer | 否 | 每页大小 | 10 |
| loginName | String | 否 | 登录账号 | admin |
| loginStatus | String | 否 | 登录状态 | 0 |
| clientType | String | 否 | 客户端类型 | WEB |
| loginIp | String | 否 | 登录IP | 127.0.0.1 |
| loginAddress | String | 否 | 登录地址 | 本地登录 |
| browser | String | 否 | 浏览器类型 | Chrome |
| os | String | 否 | 操作系统 | Windows 10 |
| beginTime | String | 否 | 开始时间 | 2024-01-01 |
| endTime | String | 否 | 结束时间 | 2024-12-31 |
**响应示例**:
```json
{
"status": 200,
"msg": "SUCCESS",
"data": {
"records": [
{
"infoId": 1,
"loginName": "admin",
"userName": "管理员",
"userId": 1,
"loginStatus": "0",
"clientType": "WEB",
"deviceName": "Windows PC",
"loginIp": "127.0.0.1",
"loginAddress": "本地登录",
"browser": "Chrome 120.0.0.0",
"os": "Windows 10",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"loginTime": "2024-07-05 10:00:00",
"logoutTime": "2024-07-05 11:00:00",
"sessionDuration": 3600,
"failureReason": "",
"remark": "登录成功",
"createBy": "system",
"createTime": "2024-07-05 10:00:00",
"updateBy": "system",
"updateTime": "2024-07-05 11:00:00"
}
],
"total": 1,
"size": 10,
"current": 1,
"pages": 1
},
"traceId": "trace-123456"
}
```
**调用示例**:
```bash
curl -X GET \
"http://localhost:18099/coder/sysLoginLog/listPage?pageNo=1&pageSize=10&loginName=admin&loginStatus=0" \
-H "Authorization: Bearer your-token-value"
```
---
### 2. 查询所有登录日志
**接口地址**: `GET /coder/sysLoginLog/list`
**接口描述**: 查询所有系统登录日志(不分页)
**是否需要认证**: 是
**权限要求**: `system:loginlog:list`
**请求参数**: 同分页查询除pageNo、pageSize外
**响应示例**:
```json
{
"status": 200,
"msg": "SUCCESS",
"data": [
{
"infoId": 1,
"loginName": "admin",
"userName": "管理员",
"userId": 1,
"loginStatus": "0",
"clientType": "WEB",
"deviceName": "Windows PC",
"loginIp": "127.0.0.1",
"loginAddress": "本地登录",
"browser": "Chrome 120.0.0.0",
"os": "Windows 10",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"loginTime": "2024-07-05 10:00:00",
"logoutTime": "2024-07-05 11:00:00",
"sessionDuration": 3600,
"failureReason": "",
"remark": "登录成功",
"createBy": "system",
"createTime": "2024-07-05 10:00:00",
"updateBy": "system",
"updateTime": "2024-07-05 11:00:00"
}
],
"traceId": "trace-123456"
}
```
**调用示例**:
```bash
curl -X GET \
"http://localhost:18099/coder/sysLoginLog/list?loginStatus=1&beginTime=2024-07-01" \
-H "Authorization: Bearer your-token-value"
```
---
### 3. 根据ID查询登录日志
**接口地址**: `GET /coder/sysLoginLog/getById/{id}`
**接口描述**: 根据日志ID查询登录日志详细信息
**是否需要认证**: 是
**权限要求**: `system:loginlog:list`
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | Long | 是 | 日志ID |
**响应示例**:
```json
{
"status": 200,
"msg": "SUCCESS",
"data": {
"infoId": 1,
"loginName": "admin",
"userName": "管理员",
"userId": 1,
"loginStatus": "0",
"clientType": "WEB",
"deviceName": "Windows PC",
"loginIp": "127.0.0.1",
"loginAddress": "本地登录",
"browser": "Chrome 120.0.0.0",
"os": "Windows 10",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"loginTime": "2024-07-05 10:00:00",
"logoutTime": "2024-07-05 11:00:00",
"sessionDuration": 3600,
"failureReason": "",
"remark": "登录成功",
"createBy": "system",
"createTime": "2024-07-05 10:00:00",
"updateBy": "system",
"updateTime": "2024-07-05 11:00:00"
},
"traceId": "trace-123456"
}
```
**调用示例**:
```bash
curl -X GET \
http://localhost:18099/coder/sysLoginLog/getById/1 \
-H "Authorization: Bearer your-token-value"
```
---
### 4. 新增登录日志
**接口地址**: `POST /coder/sysLoginLog/add`
**接口描述**: 新增系统登录日志记录
**是否需要认证**: 是
**权限要求**: `system:loginlog:add`
**请求参数**:
```json
{
"loginName": "admin",
"userName": "管理员",
"userId": 1,
"loginStatus": "0",
"clientType": "WEB",
"deviceName": "Windows PC",
"loginIp": "127.0.0.1",
"loginAddress": "本地登录",
"browser": "Chrome 120.0.0.0",
"os": "Windows 10",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"loginTime": "2024-07-05 10:00:00",
"failureReason": "",
"remark": "登录成功"
}
```
**请求参数说明**:
| 参数名 | 类型 | 必填 | 说明 | 校验规则 |
|--------|------|------|------|----------|
| loginName | String | 是 | 登录账号 | 不能为空 |
| userName | String | 否 | 用户姓名 | 可为空 |
| userId | Long | 否 | 用户ID | 有效的用户ID |
| loginStatus | String | 是 | 登录状态 | 0-成功 1-失败 |
| clientType | String | 是 | 客户端类型 | WEB, MOBILE, API |
| deviceName | String | 否 | 设备名称 | 可为空 |
| loginIp | String | 是 | 登录IP | 有效的IP地址 |
| loginAddress | String | 否 | 登录地址 | 可为空 |
| browser | String | 否 | 浏览器信息 | 可为空 |
| os | String | 否 | 操作系统 | 可为空 |
| userAgent | String | 否 | 用户代理 | 可为空 |
| loginTime | String | 是 | 登录时间 | 时间格式 |
| failureReason | String | 否 | 失败原因 | 登录失败时必填 |
| remark | String | 否 | 备注信息 | 最长500字符 |
**响应示例**:
```json
{
"status": 200,
"msg": "SUCCESS",
"data": "新增成功",
"traceId": "trace-123456"
}
```
**调用示例**:
```bash
curl -X POST \
http://localhost:18099/coder/sysLoginLog/add \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token-value" \
-d '{
"loginName": "admin",
"userName": "管理员",
"userId": 1,
"loginStatus": "0",
"clientType": "WEB",
"loginIp": "127.0.0.1",
"loginTime": "2024-07-05 10:00:00",
"remark": "登录成功"
}'
```
---
### 5. 修改登录日志
**接口地址**: `POST /coder/sysLoginLog/update`
**接口描述**: 修改系统登录日志信息(通常用于更新退出时间)
**是否需要认证**: 是
**权限要求**: `system:loginlog:edit`
**请求参数**:
```json
{
"infoId": 1,
"loginName": "admin",
"userName": "管理员",
"userId": 1,
"loginStatus": "0",
"clientType": "WEB",
"deviceName": "Windows PC",
"loginIp": "127.0.0.1",
"loginAddress": "本地登录",
"browser": "Chrome 120.0.0.0",
"os": "Windows 10",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"loginTime": "2024-07-05 10:00:00",
"logoutTime": "2024-07-05 11:00:00",
"sessionDuration": 3600,
"failureReason": "",
"remark": "正常退出"
}
```
**请求参数说明**:
| 参数名 | 类型 | 必填 | 说明 | 校验规则 |
|--------|------|------|------|----------|
| infoId | Long | 是 | 日志ID | 必须是有效的日志ID |
| logoutTime | String | 否 | 退出时间 | 时间格式 |
| sessionDuration | Integer | 否 | 会话时长(秒) | 大于等于0 |
| 其他参数 | - | - | 同新增日志 | - |
**响应示例**:
```json
{
"status": 200,
"msg": "SUCCESS",
"data": "修改成功",
"traceId": "trace-123456"
}
```
**调用示例**:
```bash
curl -X POST \
http://localhost:18099/coder/sysLoginLog/update \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token-value" \
-d '{
"infoId": 1,
"logoutTime": "2024-07-05 11:00:00",
"sessionDuration": 3600,
"remark": "正常退出"
}'
```
---
### 6. 删除登录日志
**接口地址**: `POST /coder/sysLoginLog/deleteById/{id}`
**接口描述**: 根据ID删除登录日志
**是否需要认证**: 是
**权限要求**: `system:loginlog:remove`
**路径参数**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | Long | 是 | 日志ID |
**响应示例**:
```json
{
"status": 200,
"msg": "SUCCESS",
"data": "删除成功",
"traceId": "trace-123456"
}
```
**调用示例**:
```bash
curl -X POST \
http://localhost:18099/coder/sysLoginLog/deleteById/1 \
-H "Authorization: Bearer your-token-value"
```
---
### 7. 批量删除登录日志
**接口地址**: `POST /coder/sysLoginLog/batchDelete`
**接口描述**: 批量删除登录日志
**是否需要认证**: 是
**权限要求**: `system:loginlog:remove`
**请求参数**:
```json
{
"ids": [1, 2, 3]
}
```
**请求参数说明**:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| ids | Long[] | 是 | 日志ID数组 |
**响应示例**:
```json
{
"status": 200,
"msg": "SUCCESS",
"data": "删除成功",
"traceId": "trace-123456"
}
```
**调用示例**:
```bash
curl -X POST \
http://localhost:18099/coder/sysLoginLog/batchDelete \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token-value" \
-d '{
"ids": [1, 2, 3]
}'
```
---
## 登录日志字段说明
### 基础字段
| 字段名 | 类型 | 说明 | 示例 |
|--------|------|------|------|
| infoId | Long | 日志ID | 1 |
| loginName | String | 登录账号 | admin |
| userName | String | 用户姓名 | 管理员 |
| userId | Long | 用户ID | 1 |
### 状态字段
| 字段名 | 类型 | 说明 | 示例 |
|--------|------|------|------|
| loginStatus | String | 登录状态 | 0-成功 1-失败 |
| clientType | String | 客户端类型 | WEB, MOBILE, API |
| deviceName | String | 设备名称 | Windows PC |
### 网络字段
| 字段名 | 类型 | 说明 | 示例 |
|--------|------|------|------|
| loginIp | String | 登录IP地址 | 127.0.0.1 |
| loginAddress | String | 登录地理位置 | 本地登录 |
| userAgent | String | 用户代理字符串 | Mozilla/5.0... |
### 环境字段
| 字段名 | 类型 | 说明 | 示例 |
|--------|------|------|------|
| browser | String | 浏览器信息 | Chrome 120.0.0.0 |
| os | String | 操作系统 | Windows 10 |
### 时间字段
| 字段名 | 类型 | 说明 | 示例 |
|--------|------|------|------|
| loginTime | String | 登录时间 | 2024-07-05 10:00:00 |
| logoutTime | String | 退出时间 | 2024-07-05 11:00:00 |
| sessionDuration | Integer | 会话时长(秒) | 3600 |
### 其他字段
| 字段名 | 类型 | 说明 | 示例 |
|--------|------|------|------|
| failureReason | String | 失败原因 | 密码错误 |
| remark | String | 备注信息 | 登录成功 |
---
## 数据字典
### 登录状态 (loginStatus)
| 值 | 说明 |
|----|------|
| 0 | 登录成功 |
| 1 | 登录失败 |
### 客户端类型 (clientType)
| 值 | 说明 |
|----|------|
| WEB | 网页端 |
| MOBILE | 移动端 |
| API | 接口调用 |
| DESKTOP | 桌面应用 |
| WECHAT | 微信小程序 |
### 常见失败原因
| 失败原因 | 说明 |
|----------|------|
| 用户不存在 | 登录账号不存在 |
| 密码错误 | 登录密码不正确 |
| 验证码错误 | 验证码输入错误 |
| 账号被禁用 | 用户账号被禁用 |
| 账号被锁定 | 用户账号被锁定 |
| IP被限制 | 登录IP被限制 |
| 设备被限制 | 登录设备被限制 |
| 会话过期 | 用户会话已过期 |
---
## 日志记录机制
### 1. 自动记录
```java
@Component
@Slf4j
public class LoginLogService {
/**
* 记录登录成功日志
*/
public void recordLoginSuccess(String loginName, HttpServletRequest request) {
try {
SysLoginLog loginLog = new SysLoginLog();
// 基础信息
loginLog.setLoginName(loginName);
loginLog.setUserId(getCurrentUserId(loginName));
loginLog.setUserName(getCurrentUserName(loginName));
loginLog.setLoginStatus("0");
loginLog.setLoginTime(LocalDateTime.now());
// 网络信息
loginLog.setLoginIp(getClientIP(request));
loginLog.setLoginAddress(getAddressByIP(loginLog.getLoginIp()));
// 客户端信息
loginLog.setClientType(getClientType(request));
loginLog.setUserAgent(request.getHeader("User-Agent"));
loginLog.setBrowser(getBrowserInfo(request));
loginLog.setOs(getOSInfo(request));
loginLog.setDeviceName(getDeviceName(request));
// 其他信息
loginLog.setRemark("登录成功");
loginLog.setCreateBy("system");
loginLog.setCreateTime(LocalDateTime.now());
// 保存日志
sysLoginLogMapper.insert(loginLog);
} catch (Exception e) {
log.error("记录登录成功日志失败", e);
}
}
/**
* 记录登录失败日志
*/
public void recordLoginFailure(String loginName, String failureReason, HttpServletRequest request) {
try {
SysLoginLog loginLog = new SysLoginLog();
// 基础信息
loginLog.setLoginName(loginName);
loginLog.setLoginStatus("1");
loginLog.setLoginTime(LocalDateTime.now());
loginLog.setFailureReason(failureReason);
// 网络信息
loginLog.setLoginIp(getClientIP(request));
loginLog.setLoginAddress(getAddressByIP(loginLog.getLoginIp()));
// 客户端信息
loginLog.setClientType(getClientType(request));
loginLog.setUserAgent(request.getHeader("User-Agent"));
loginLog.setBrowser(getBrowserInfo(request));
loginLog.setOs(getOSInfo(request));
loginLog.setDeviceName(getDeviceName(request));
// 其他信息
loginLog.setRemark("登录失败:" + failureReason);
loginLog.setCreateBy("system");
loginLog.setCreateTime(LocalDateTime.now());
// 保存日志
sysLoginLogMapper.insert(loginLog);
} catch (Exception e) {
log.error("记录登录失败日志失败", e);
}
}
/**
* 记录退出登录日志
*/
public void recordLogout(String loginName, LocalDateTime loginTime) {
try {
// 查找对应的登录日志
SysLoginLog loginLog = sysLoginLogMapper.selectOne(
new LambdaQueryWrapper<SysLoginLog>()
.eq(SysLoginLog::getLoginName, loginName)
.eq(SysLoginLog::getLoginTime, loginTime)
.eq(SysLoginLog::getLoginStatus, "0")
.isNull(SysLoginLog::getLogoutTime)
.last("ORDER BY create_time DESC LIMIT 1")
);
if (loginLog != null) {
LocalDateTime logoutTime = LocalDateTime.now();
long sessionDuration = Duration.between(loginLog.getLoginTime(), logoutTime).getSeconds();
loginLog.setLogoutTime(logoutTime);
loginLog.setSessionDuration((int) sessionDuration);
loginLog.setRemark("正常退出");
loginLog.setUpdateBy("system");
loginLog.setUpdateTime(LocalDateTime.now());
sysLoginLogMapper.updateById(loginLog);
}
} catch (Exception e) {
log.error("记录退出登录日志失败", e);
}
}
/**
* 获取客户端IP
*/
private String getClientIP(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
/**
* 解析浏览器信息
*/
private String getBrowserInfo(HttpServletRequest request) {
String userAgent = request.getHeader("User-Agent");
if (userAgent == null) {
return "Unknown";
}
if (userAgent.contains("Chrome")) {
return "Chrome";
} else if (userAgent.contains("Firefox")) {
return "Firefox";
} else if (userAgent.contains("Safari")) {
return "Safari";
} else if (userAgent.contains("Edge")) {
return "Edge";
} else if (userAgent.contains("IE")) {
return "Internet Explorer";
} else {
return "Other";
}
}
/**
* 解析操作系统信息
*/
private String getOSInfo(HttpServletRequest request) {
String userAgent = request.getHeader("User-Agent");
if (userAgent == null) {
return "Unknown";
}
if (userAgent.contains("Windows NT 10.0")) {
return "Windows 10";
} else if (userAgent.contains("Windows NT 6.3")) {
return "Windows 8.1";
} else if (userAgent.contains("Windows NT 6.2")) {
return "Windows 8";
} else if (userAgent.contains("Windows NT 6.1")) {
return "Windows 7";
} else if (userAgent.contains("Mac OS X")) {
return "Mac OS";
} else if (userAgent.contains("Linux")) {
return "Linux";
} else if (userAgent.contains("Android")) {
return "Android";
} else if (userAgent.contains("iPhone") || userAgent.contains("iPad")) {
return "iOS";
} else {
return "Other";
}
}
}
```
### 2. 异步处理
```java
@Service
public class AsyncLoginLogService {
@Async("taskExecutor")
public void recordLoginLogAsync(SysLoginLog loginLog) {
try {
// 异步记录登录日志
sysLoginLogMapper.insert(loginLog);
// 更新用户登录信息
updateUserLoginInfo(loginLog);
// 检查异常登录
checkAbnormalLogin(loginLog);
} catch (Exception e) {
log.error("异步记录登录日志失败", e);
}
}
/**
* 检查异常登录
*/
private void checkAbnormalLogin(SysLoginLog loginLog) {
// 检查IP异常
if (isAbnormalIP(loginLog.getLoginIp(), loginLog.getLoginName())) {
sendSecurityAlert("检测到异常IP登录", loginLog);
}
// 检查设备异常
if (isAbnormalDevice(loginLog.getUserAgent(), loginLog.getLoginName())) {
sendSecurityAlert("检测到异常设备登录", loginLog);
}
// 检查时间异常
if (isAbnormalTime(loginLog.getLoginTime(), loginLog.getLoginName())) {
sendSecurityAlert("检测到异常时间登录", loginLog);
}
}
}
```
---
## 统计分析功能
### 1. 登录统计
```java
/**
* 登录统计服务
*/
@Service
public class LoginStatisticsService {
/**
* 获取登录成功率统计
*/
public LoginSuccessRateVO getLoginSuccessRate(String beginTime, String endTime) {
// 查询总登录次数
long totalCount = sysLoginLogMapper.selectCount(
new LambdaQueryWrapper<SysLoginLog>()
.between(SysLoginLog::getLoginTime, beginTime, endTime)
);
// 查询成功登录次数
long successCount = sysLoginLogMapper.selectCount(
new LambdaQueryWrapper<SysLoginLog>()
.eq(SysLoginLog::getLoginStatus, "0")
.between(SysLoginLog::getLoginTime, beginTime, endTime)
);
// 计算成功率
double successRate = totalCount > 0 ? (double) successCount / totalCount * 100 : 0;
return LoginSuccessRateVO.builder()
.totalCount(totalCount)
.successCount(successCount)
.failureCount(totalCount - successCount)
.successRate(successRate)
.build();
}
/**
* 获取每日登录统计
*/
public List<DailyLoginStatVO> getDailyLoginStat(String beginTime, String endTime) {
return sysLoginLogMapper.selectDailyLoginStat(beginTime, endTime);
}
/**
* 获取客户端类型统计
*/
public List<ClientTypeStatVO> getClientTypeStat(String beginTime, String endTime) {
return sysLoginLogMapper.selectClientTypeStat(beginTime, endTime);
}
}
```
### 2. 安全监控
```java
/**
* 安全监控服务
*/
@Service
public class SecurityMonitorService {
/**
* 检测暴力破解
*/
public void detectBruteForce() {
// 查询5分钟内失败次数超过5次的IP
List<String> suspiciousIPs = sysLoginLogMapper.selectSuspiciousIPs();
for (String ip : suspiciousIPs) {
// 加入黑名单
addToBlacklist(ip);
// 发送告警
sendSecurityAlert("检测到暴力破解攻击", ip);
}
}
/**
* 检测异地登录
*/
public void detectRemoteLogin() {
// 查询用户最近登录地址
List<SysLoginLog> recentLogins = sysLoginLogMapper.selectRecentLogins();
for (SysLoginLog loginLog : recentLogins) {
String lastLoginAddress = getLastLoginAddress(loginLog.getLoginName());
if (!loginLog.getLoginAddress().equals(lastLoginAddress)) {
// 发送异地登录通知
sendRemoteLoginNotification(loginLog);
}
}
}
}
```
---
## 错误码说明
| 错误码 | 错误信息 | 说明 |
|--------|----------|------|
| 400 | 登录账号不能为空 | 登录账号为空 |
| 400 | 登录状态不能为空 | 登录状态为空 |
| 400 | 登录时间不能为空 | 登录时间为空 |
| 400 | 登录IP不能为空 | 登录IP为空 |
| 400 | 日志不存在 | 日志ID不存在 |
| 400 | 时间格式错误 | 时间格式不正确 |
| 401 | 当前会话未登录 | 未登录或Token无效 |
| 403 | 权限不足 | 没有相应的操作权限 |
| 500 | 日志记录失败 | 日志保存失败 |
| 500 | 系统异常 | 服务器内部错误 |
---
## 日志清理策略
### 1. 定时清理
```java
@Component
public class LoginLogCleanupTask {
/**
* 每天凌晨2点清理30天前的登录日志
*/
@Scheduled(cron = "0 0 2 * * ?")
public void cleanupOldLogs() {
try {
LocalDateTime cutoffTime = LocalDateTime.now().minusDays(30);
int deletedCount = sysLoginLogMapper.delete(
new LambdaQueryWrapper<SysLoginLog>()
.lt(SysLoginLog::getCreateTime, cutoffTime)
);
log.info("清理登录日志完成,删除{}条记录", deletedCount);
} catch (Exception e) {
log.error("清理登录日志失败", e);
}
}
/**
* 归档登录日志
*/
@Scheduled(cron = "0 0 1 1 * ?") // 每月1号凌晨1点执行
public void archiveLogs() {
try {
LocalDateTime lastMonth = LocalDateTime.now().minusMonths(1);
// 归档上个月的日志到历史表
sysLoginLogMapper.archiveLogsToHistory(lastMonth);
log.info("归档登录日志完成");
} catch (Exception e) {
log.error("归档登录日志失败", e);
}
}
}
```
### 2. 日志配置
```yaml
# application.yml
logging:
login-log:
# 是否启用登录日志
enabled: true
# 日志保留天数
retention-days: 90
# 是否记录成功登录
log-success: true
# 是否记录失败登录
log-failure: true
# 是否异步记录
async: true
# 是否启用IP地址解析
resolve-address: true
# 是否启用安全监控
security-monitor: true
```
---
## 使用建议
### 1. 日志管理
- **合理保留期**: 根据业务需要设置日志保留期
- **定期清理**: 定期清理过期日志释放存储空间
- **分表存储**: 大量日志可考虑按月分表存储
- **归档备份**: 重要日志定期归档备份
### 2. 安全监控
- **实时监控**: 实时监控异常登录行为
- **告警机制**: 建立完善的安全告警机制
- **自动响应**: 对可疑行为自动采取防护措施
- **定期分析**: 定期分析登录日志发现安全趋势
### 3. 性能优化
- **异步记录**: 使用异步方式记录日志避免影响登录性能
- **批量处理**: 批量处理日志数据提高效率
- **索引优化**: 为查询字段建立合适索引
- **分页查询**: 大数据量查询使用分页
### 4. 隐私保护
- **敏感信息**: 不记录密码等敏感信息
- **数据脱敏**: 对部分信息进行脱敏处理
- **访问控制**: 严格控制日志访问权限
- **合规要求**: 遵守相关数据保护法规
---
## 注意事项
1. **日志完整性**: 确保登录日志记录的完整性和准确性
2. **性能影响**: 日志记录不应影响用户登录体验
3. **存储空间**: 注意日志存储空间的管理和清理
4. **安全防护**: 防止日志被恶意篡改或删除
5. **隐私保护**: 不记录用户密码等敏感信息
6. **异常处理**: 日志记录失败不应影响正常业务
7. **监控告警**: 建立异常登录的监控告警机制
8. **数据备份**: 重要日志数据需要备份
9. **合规要求**: 遵守相关法律法规对日志的要求
10. **访问审计**: 对日志访问行为也要进行审计