feat(auth): 新增登录日志模块并记录登录失败
- 新增 SystemLoginLog 实体、Mapper、Service 及 XML 配置 - UserController 登录接口补充异常捕获与失败日志记录 - 删除旧压缩日志,新增最新日志文件 - 补充 AGENTS.md 使用说明文档
This commit is contained in:
195
AGENTS.md
Normal file
195
AGENTS.md
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
This is a Spring Boot 2.7.2 application serving as a multi-tenant system with AI integration capabilities. The application focuses on host/streamer data management with AI chat functionality, built on a layered architecture pattern.
|
||||||
|
|
||||||
|
**Key Technologies:**
|
||||||
|
- Spring Boot 2.7.2 with Java 17
|
||||||
|
- MyBatis-Plus 3.5.2 for data access
|
||||||
|
- SA-Token 1.44.0 for authentication
|
||||||
|
- Redis for distributed caching and session management
|
||||||
|
- RabbitMQ for message-driven architecture
|
||||||
|
- Knife4j 4.4.0 for API documentation
|
||||||
|
- MySQL database
|
||||||
|
|
||||||
|
## Build and Run Commands
|
||||||
|
|
||||||
|
### Development
|
||||||
|
```bash
|
||||||
|
# Run the application (dev profile is default)
|
||||||
|
mvn spring-boot:run
|
||||||
|
|
||||||
|
# Build the project
|
||||||
|
mvn clean package
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
mvn test
|
||||||
|
|
||||||
|
# Skip tests during build
|
||||||
|
mvn clean package -DskipTests
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Setup
|
||||||
|
```bash
|
||||||
|
# Initialize database using the SQL script
|
||||||
|
mysql -u root -p < sql/create_table.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important:** Update database credentials in `src/main/resources/application.yml` before running.
|
||||||
|
|
||||||
|
### Access Points
|
||||||
|
- Application: http://localhost:8101/api
|
||||||
|
- API Documentation: http://localhost:8101/api/doc.html
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Layered Structure
|
||||||
|
The codebase follows a standard layered architecture:
|
||||||
|
|
||||||
|
**Controller Layer** (`controller/`) → **Service Layer** (`service/`) → **Mapper Layer** (`mapper/`) → **Database**
|
||||||
|
|
||||||
|
### Key Packages
|
||||||
|
- `annotation/` - Custom annotations like `@AuthCheck` for role-based access control
|
||||||
|
- `aop/` - Aspect-oriented programming for cross-cutting concerns (logging, auth)
|
||||||
|
- `config/` - Spring configuration classes for SA-Token, MyBatis-Plus, Redis, RabbitMQ, CORS
|
||||||
|
- `model/entity/` - Database entities mapped with MyBatis-Plus
|
||||||
|
- `model/dto/` - Data Transfer Objects for API requests
|
||||||
|
- `model/vo/` - View Objects for API responses
|
||||||
|
- `model/enums/` - Enumerations including `LoginSceneEnum` for multi-scenario authentication
|
||||||
|
- `exception/` - Custom exception handling with `GlobalExceptionHandler`
|
||||||
|
- `utils/` - Utility classes for common operations
|
||||||
|
|
||||||
|
### Authentication System (SA-Token)
|
||||||
|
|
||||||
|
The application uses SA-Token with **multiple login scenarios**:
|
||||||
|
|
||||||
|
1. **HOST** - Host/streamer login (`/user/doLogin`)
|
||||||
|
2. **BIG_BROTHER** - Admin tenant login (`/user/bigbrother-doLogin`)
|
||||||
|
3. **AI_CHAT** - AI chat login (`/user/aiChat-doLogin`)
|
||||||
|
4. **WEB_AI** - Web AI login (`/user/webAi-doLogin`)
|
||||||
|
|
||||||
|
Each scenario uses a different SA-Token login mode (defined in `LoginSceneEnum`) and has its own role validation logic in `SystemUsersService`.
|
||||||
|
|
||||||
|
**Token Configuration:**
|
||||||
|
- Token name: `vvtoken`
|
||||||
|
- Timeout: 172800 seconds (2 days)
|
||||||
|
- Non-concurrent login (new login kicks out old session)
|
||||||
|
- Token style: random-128
|
||||||
|
|
||||||
|
**Public Endpoints** (no authentication required):
|
||||||
|
- All Swagger/Knife4j documentation endpoints
|
||||||
|
- Login endpoints for all scenarios
|
||||||
|
- `/tenant/get-id-by-name`
|
||||||
|
- `/error`
|
||||||
|
|
||||||
|
See `SaTokenConfigure.java:35` for the complete list of excluded paths.
|
||||||
|
|
||||||
|
### Database Layer (MyBatis-Plus)
|
||||||
|
|
||||||
|
**Configuration Notes:**
|
||||||
|
- Camel case to underscore mapping is **disabled** (`map-underscore-to-camel-case: false`)
|
||||||
|
- Field names in entities must match database column names exactly
|
||||||
|
- Logical deletion is enabled globally via `isDelete` field
|
||||||
|
- Pagination is configured via `PaginationInnerInterceptor`
|
||||||
|
|
||||||
|
**Custom Mappers:**
|
||||||
|
- Complex queries use XML mappers in `src/main/resources/mapper/`
|
||||||
|
- Simple CRUD operations use MyBatis-Plus built-in methods
|
||||||
|
|
||||||
|
### Message Queue (RabbitMQ)
|
||||||
|
|
||||||
|
The application uses **HeadersExchange** pattern for message routing. Configuration is in `RabbitMQConfig.java`.
|
||||||
|
|
||||||
|
**Key Queues:**
|
||||||
|
- Multiple business-specific queues with persistent messages
|
||||||
|
- Manual acknowledgment mode
|
||||||
|
- JSON message serialization with Jackson
|
||||||
|
|
||||||
|
### Redis Integration
|
||||||
|
|
||||||
|
Redis is used for:
|
||||||
|
- Distributed session storage (Spring Session)
|
||||||
|
- SA-Token session management
|
||||||
|
- Custom caching needs
|
||||||
|
|
||||||
|
**Configuration:** See `RedisConfig.java` for JSON serialization setup with Jackson.
|
||||||
|
|
||||||
|
### Multi-Tenant Architecture
|
||||||
|
|
||||||
|
The system supports multi-tenancy with:
|
||||||
|
- `SystemTenant` entity for tenant management
|
||||||
|
- `SystemUsers` entity with tenant associations
|
||||||
|
- Tenant-specific authentication flows (BIG_BROTHER scenario)
|
||||||
|
- Tenant ID retrieval endpoint: `/tenant/get-id-by-name`
|
||||||
|
|
||||||
|
## Development Guidelines
|
||||||
|
|
||||||
|
### Adding New Endpoints
|
||||||
|
|
||||||
|
1. Create/update DTO in `model/dto/` for request validation
|
||||||
|
2. Create/update VO in `model/vo/` for response formatting
|
||||||
|
3. Add service method in appropriate service interface and implementation
|
||||||
|
4. Add controller endpoint with proper `@AuthCheck` annotation if authentication is required
|
||||||
|
5. If endpoint should be public, add path to `SaTokenConfigure.getExcludePaths()`
|
||||||
|
|
||||||
|
### Working with Authentication
|
||||||
|
|
||||||
|
**Role-based Access Control:**
|
||||||
|
```java
|
||||||
|
@AuthCheck(mustRole = UserRoleEnum.ADMIN)
|
||||||
|
public BaseResponse<String> adminOnlyEndpoint() {
|
||||||
|
// Implementation
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Multi-scenario Login:**
|
||||||
|
- Use `LoginSceneEnum` to determine the login scenario
|
||||||
|
- Each scenario has its own SA-Token mode and role validation
|
||||||
|
- Logout endpoints are scenario-specific (e.g., `/user/aiChat-logout`)
|
||||||
|
|
||||||
|
### Database Entities
|
||||||
|
|
||||||
|
**Important:** When creating or modifying entities:
|
||||||
|
- Use `@TableName` to specify exact table name
|
||||||
|
- Use `@TableField` for fields that don't follow naming conventions
|
||||||
|
- Include `isDelete` field for logical deletion support
|
||||||
|
- Add `createTime` and `updateTime` with appropriate defaults
|
||||||
|
|
||||||
|
### Code Generation
|
||||||
|
|
||||||
|
The project includes FreeMarker-based code generation utilities in the `generate/` package for scaffolding new modules.
|
||||||
|
|
||||||
|
## Configuration Files
|
||||||
|
|
||||||
|
- `application.yml` - Main configuration with SA-Token, database, and server settings
|
||||||
|
- `application-dev.yml` - Development environment overrides
|
||||||
|
- `application-prod.yml` - Production environment overrides
|
||||||
|
|
||||||
|
**Active Profile:** Defaults to `dev` (see `application.yml:9`)
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
- **Redis:** Currently disabled in `MainApplication.java`. To enable, remove `RedisAutoConfiguration` from the `exclude` list and uncomment session store-type in `application.yml:17`
|
||||||
|
- **MyBatis Logging:** Disabled by default in static block of `MainApplication.java:24-27`
|
||||||
|
- **Context Path:** All endpoints are prefixed with `/api` (see `application.yml:42`)
|
||||||
|
- **File Upload Limit:** 10MB (see `application.yml:37`)
|
||||||
|
- **CORS:** Configured to allow all origins in `SaTokenConfigure.corsHandle()`
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Tests are located in `src/test/java/`. The project uses Spring Boot Test framework.
|
||||||
|
|
||||||
|
Run specific test class:
|
||||||
|
```bash
|
||||||
|
mvn test -Dtest=ClassName
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Issues
|
||||||
|
|
||||||
|
1. **Authentication Errors:** Verify the correct login endpoint is being used for the scenario (HOST, BIG_BROTHER, AI_CHAT, WEB_AI)
|
||||||
|
2. **Database Connection:** Ensure MySQL is running and credentials in `application.yml` are correct
|
||||||
|
3. **Redis Connection:** If Redis features are needed, enable Redis in `MainApplication.java` and configure connection in `application.yml`
|
||||||
|
4. **Field Mapping Issues:** Remember that camel-to-underscore mapping is disabled; field names must match exactly
|
||||||
@@ -1,18 +1,11 @@
|
|||||||
package com.yupi.springbootinit.controller;
|
package com.yupi.springbootinit.controller;
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
|
||||||
import com.yupi.springbootinit.common.BaseResponse;
|
import com.yupi.springbootinit.common.BaseResponse;
|
||||||
import com.yupi.springbootinit.common.ErrorCode;
|
|
||||||
import com.yupi.springbootinit.common.ResultUtils;
|
import com.yupi.springbootinit.common.ResultUtils;
|
||||||
import com.yupi.springbootinit.exception.BusinessException;
|
|
||||||
import com.yupi.springbootinit.model.dto.user.SystemUsersDTO;
|
import com.yupi.springbootinit.model.dto.user.SystemUsersDTO;
|
||||||
import com.yupi.springbootinit.model.entity.SystemUsers;
|
|
||||||
import com.yupi.springbootinit.model.enums.CommonStatusEnum;
|
|
||||||
import com.yupi.springbootinit.model.enums.LoginSceneEnum;
|
import com.yupi.springbootinit.model.enums.LoginSceneEnum;
|
||||||
import com.yupi.springbootinit.model.vo.user.SystemUsersVO;
|
import com.yupi.springbootinit.model.vo.user.SystemUsersVO;
|
||||||
import com.yupi.springbootinit.service.SystemUsersService;
|
import com.yupi.springbootinit.service.SystemLoginLogService;
|
||||||
import com.yupi.springbootinit.service.impl.LoginService;
|
import com.yupi.springbootinit.service.impl.LoginService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -34,10 +27,20 @@ public class UserController {
|
|||||||
@Resource
|
@Resource
|
||||||
private LoginService loginService;
|
private LoginService loginService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SystemLoginLogService systemLoginLogService;
|
||||||
|
|
||||||
// 用户登陆接口
|
// 用户登陆接口
|
||||||
@PostMapping("doLogin")
|
@PostMapping("doLogin")
|
||||||
public BaseResponse<SystemUsersVO> doLogin(@RequestBody SystemUsersDTO usersDTO) {
|
public BaseResponse<SystemUsersVO> doLogin(@RequestBody SystemUsersDTO usersDTO) {
|
||||||
return ResultUtils.success(loginService.login(LoginSceneEnum.HOST, usersDTO));
|
try {
|
||||||
|
SystemUsersVO usersVO = loginService.login(LoginSceneEnum.HOST, usersDTO);
|
||||||
|
systemLoginLogService.recordDoLoginLog(usersDTO, usersVO, true);
|
||||||
|
return ResultUtils.success(usersVO);
|
||||||
|
} catch (RuntimeException exception) {
|
||||||
|
recordFailedDoLoginLog(usersDTO, exception);
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -73,4 +76,12 @@ public class UserController {
|
|||||||
return ResultUtils.success(loginService.bigBrotherLogout(usersDTO));
|
return ResultUtils.success(loginService.bigBrotherLogout(usersDTO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void recordFailedDoLoginLog(SystemUsersDTO usersDTO, RuntimeException exception) {
|
||||||
|
try {
|
||||||
|
systemLoginLogService.recordDoLoginLog(usersDTO, null, false);
|
||||||
|
} catch (RuntimeException logException) {
|
||||||
|
logException.addSuppressed(exception);
|
||||||
|
throw logException;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.yupi.springbootinit.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.yupi.springbootinit.model.entity.SystemLoginLog;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author: ziin
|
||||||
|
* @date: 2026/3/10 11:32
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface SystemLoginLogMapper extends BaseMapper<SystemLoginLog> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package com.yupi.springbootinit.model.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author: ziin
|
||||||
|
* @date: 2026/3/10 11:32
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统访问记录
|
||||||
|
*/
|
||||||
|
@ApiModel(description="系统访问记录")
|
||||||
|
@Data
|
||||||
|
@TableName(value = "system_login_log")
|
||||||
|
public class SystemLoginLog {
|
||||||
|
/**
|
||||||
|
* 访问ID
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
@ApiModelProperty(value="访问ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志类型
|
||||||
|
*/
|
||||||
|
@TableField(value = "log_type")
|
||||||
|
@ApiModelProperty(value="日志类型")
|
||||||
|
private Long logType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 链路追踪编号
|
||||||
|
*/
|
||||||
|
@TableField(value = "trace_id")
|
||||||
|
@ApiModelProperty(value="链路追踪编号")
|
||||||
|
private String traceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
@TableField(value = "user_id")
|
||||||
|
@ApiModelProperty(value="用户编号")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
|
@TableField(value = "user_type")
|
||||||
|
@ApiModelProperty(value="用户类型")
|
||||||
|
private Byte userType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户账号
|
||||||
|
*/
|
||||||
|
@TableField(value = "username")
|
||||||
|
@ApiModelProperty(value="用户账号")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登陆结果
|
||||||
|
*/
|
||||||
|
@TableField(value = "`result`")
|
||||||
|
@ApiModelProperty(value="登陆结果")
|
||||||
|
private Byte result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户 IP
|
||||||
|
*/
|
||||||
|
@TableField(value = "user_ip")
|
||||||
|
@ApiModelProperty(value="用户 IP")
|
||||||
|
private String userIp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 浏览器 UA
|
||||||
|
*/
|
||||||
|
@TableField(value = "user_agent")
|
||||||
|
@ApiModelProperty(value="浏览器 UA")
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建者
|
||||||
|
*/
|
||||||
|
@TableField(value = "creator")
|
||||||
|
@ApiModelProperty(value="创建者")
|
||||||
|
private String creator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "create_time")
|
||||||
|
@ApiModelProperty(value="创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新者
|
||||||
|
*/
|
||||||
|
@TableField(value = "updater")
|
||||||
|
@ApiModelProperty(value="更新者")
|
||||||
|
private String updater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "update_time")
|
||||||
|
@ApiModelProperty(value="更新时间")
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否删除
|
||||||
|
*/
|
||||||
|
@TableField(value = "deleted")
|
||||||
|
@ApiModelProperty(value="是否删除")
|
||||||
|
private Boolean deleted;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户编号
|
||||||
|
*/
|
||||||
|
@TableField(value = "tenant_id")
|
||||||
|
@ApiModelProperty(value="租户编号")
|
||||||
|
private Long tenantId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.yupi.springbootinit.service;
|
||||||
|
|
||||||
|
import com.yupi.springbootinit.model.entity.SystemLoginLog;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.yupi.springbootinit.model.dto.user.SystemUsersDTO;
|
||||||
|
import com.yupi.springbootinit.model.vo.user.SystemUsersVO;
|
||||||
|
/*
|
||||||
|
* @author: ziin
|
||||||
|
* @date: 2026/3/10 11:32
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface SystemLoginLogService extends IService<SystemLoginLog>{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录主播端 doLogin 登录日志
|
||||||
|
*
|
||||||
|
* @param usersDTO 登录请求参数
|
||||||
|
* @param usersVO 登录成功后的用户信息,失败时为 null
|
||||||
|
* @param success 是否登录成功
|
||||||
|
*/
|
||||||
|
void recordDoLoginLog(SystemUsersDTO usersDTO, SystemUsersVO usersVO, boolean success);
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.yupi.springbootinit.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.yupi.springbootinit.mapper.SystemLoginLogMapper;
|
||||||
|
import com.yupi.springbootinit.model.dto.user.SystemUsersDTO;
|
||||||
|
import com.yupi.springbootinit.model.entity.SystemLoginLog;
|
||||||
|
import com.yupi.springbootinit.model.vo.user.SystemUsersVO;
|
||||||
|
import com.yupi.springbootinit.service.SystemLoginLogService;
|
||||||
|
import com.yupi.springbootinit.utils.NetUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
/*
|
||||||
|
* @author: ziin
|
||||||
|
* @date: 2026/3/10 11:32
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SystemLoginLogServiceImpl extends ServiceImpl<SystemLoginLogMapper, SystemLoginLog> implements SystemLoginLogService{
|
||||||
|
|
||||||
|
private static final Long HOST_LOGIN_LOG_TYPE = 1L;
|
||||||
|
private static final Byte LOGIN_SUCCESS = 1;
|
||||||
|
private static final Byte LOGIN_FAILURE = 0;
|
||||||
|
private static final String USER_AGENT_HEADER = "User-Agent";
|
||||||
|
private static final String TRACE_ID_HEADER = "X-Trace-Id";
|
||||||
|
private static final String SYSTEM_OPERATOR = "system";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recordDoLoginLog(SystemUsersDTO usersDTO, SystemUsersVO usersVO, boolean success) {
|
||||||
|
HttpServletRequest request = getCurrentRequest();
|
||||||
|
Date now = new Date();
|
||||||
|
SystemLoginLog loginLog = new SystemLoginLog();
|
||||||
|
loginLog.setLogType(HOST_LOGIN_LOG_TYPE);
|
||||||
|
loginLog.setTraceId(resolveTraceId(request));
|
||||||
|
loginLog.setUserId(usersVO == null ? null : usersVO.getId());
|
||||||
|
loginLog.setUsername(resolveUsername(usersDTO, usersVO));
|
||||||
|
loginLog.setResult(success ? LOGIN_SUCCESS : LOGIN_FAILURE);
|
||||||
|
loginLog.setUserIp(NetUtils.getIpAddress(request));
|
||||||
|
loginLog.setUserAgent(request.getHeader(USER_AGENT_HEADER));
|
||||||
|
loginLog.setCreator(SYSTEM_OPERATOR);
|
||||||
|
loginLog.setCreateTime(now);
|
||||||
|
loginLog.setUpdater(SYSTEM_OPERATOR);
|
||||||
|
loginLog.setUpdateTime(now);
|
||||||
|
loginLog.setDeleted(Boolean.FALSE);
|
||||||
|
loginLog.setTenantId(resolveTenantId(usersDTO, usersVO));
|
||||||
|
boolean saved = save(loginLog);
|
||||||
|
if (!saved) {
|
||||||
|
throw new IllegalStateException("保存 doLogin 登录日志失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpServletRequest getCurrentRequest() {
|
||||||
|
ServletRequestAttributes attributes =
|
||||||
|
(ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
|
||||||
|
return attributes.getRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveTraceId(HttpServletRequest request) {
|
||||||
|
String traceId = request.getHeader(TRACE_ID_HEADER);
|
||||||
|
if (traceId == null || traceId.isBlank()) {
|
||||||
|
return UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
return traceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveUsername(SystemUsersDTO usersDTO, SystemUsersVO usersVO) {
|
||||||
|
if (usersVO != null && usersVO.getUsername() != null) {
|
||||||
|
return usersVO.getUsername();
|
||||||
|
}
|
||||||
|
return usersDTO.getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long resolveTenantId(SystemUsersDTO usersDTO, SystemUsersVO usersVO) {
|
||||||
|
if (usersVO != null && usersVO.getTenantId() != null) {
|
||||||
|
return usersVO.getTenantId();
|
||||||
|
}
|
||||||
|
return usersDTO.getTenantId();
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/main/resources/mapper/SystemLoginLogMapper.xml
Normal file
28
src/main/resources/mapper/SystemLoginLogMapper.xml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.yupi.springbootinit.mapper.SystemLoginLogMapper">
|
||||||
|
<resultMap id="BaseResultMap" type="com.yupi.springbootinit.model.entity.SystemLoginLog">
|
||||||
|
<!--@mbg.generated-->
|
||||||
|
<!--@Table system_login_log-->
|
||||||
|
<id column="id" jdbcType="BIGINT" property="id" />
|
||||||
|
<result column="log_type" jdbcType="BIGINT" property="logType" />
|
||||||
|
<result column="trace_id" jdbcType="VARCHAR" property="traceId" />
|
||||||
|
<result column="user_id" jdbcType="BIGINT" property="userId" />
|
||||||
|
<result column="user_type" jdbcType="TINYINT" property="userType" />
|
||||||
|
<result column="username" jdbcType="VARCHAR" property="username" />
|
||||||
|
<result column="result" jdbcType="TINYINT" property="result" />
|
||||||
|
<result column="user_ip" jdbcType="VARCHAR" property="userIp" />
|
||||||
|
<result column="user_agent" jdbcType="VARCHAR" property="userAgent" />
|
||||||
|
<result column="creator" jdbcType="VARCHAR" property="creator" />
|
||||||
|
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||||
|
<result column="updater" jdbcType="VARCHAR" property="updater" />
|
||||||
|
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
|
||||||
|
<result column="deleted" jdbcType="BIT" property="deleted" />
|
||||||
|
<result column="tenant_id" jdbcType="BIGINT" property="tenantId" />
|
||||||
|
</resultMap>
|
||||||
|
<sql id="Base_Column_List">
|
||||||
|
<!--@mbg.generated-->
|
||||||
|
id, log_type, trace_id, user_id, user_type, username, `result`, user_ip, user_agent,
|
||||||
|
creator, create_time, updater, update_time, deleted, tenant_id
|
||||||
|
</sql>
|
||||||
|
</mapper>
|
||||||
Binary file not shown.
Reference in New Issue
Block a user