添加登录时日志存储,新增查询登陆日志

liweidong
ShiJiuZhou 2 months ago
parent 98fc64576d
commit 4fbb565353
  1. 39
      blade-auth/src/main/java/org/springblade/auth/handler/BladeAuthorizationHandler.java
  2. 15
      blade-ops/blade-log/src/main/java/org/springblade/core/log/controller/LogApiController.java
  3. 39
      blade-ops/blade-log/src/main/java/org/springblade/core/log/pojo/dto/UserLoginStatsDTO.java
  4. 10
      blade-ops/blade-log/src/main/java/org/springblade/core/log/service/ILogApiService.java
  5. 42
      blade-ops/blade-log/src/main/java/org/springblade/core/log/service/impl/LogApiServiceImpl.java

@ -25,10 +25,13 @@
*/
package org.springblade.auth.handler;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.constant.TenantConstant;
import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.log.logger.BladeLogger;
import org.springblade.core.oauth2.exception.ExceptionCode;
import org.springblade.core.oauth2.handler.AbstractAuthorizationHandler;
import org.springblade.core.oauth2.props.OAuth2Properties;
@ -42,6 +45,10 @@ import org.springblade.core.tool.utils.DesUtil;
import org.springblade.core.tool.utils.SM2Util;
import org.springblade.system.cache.SysCache;
import org.springblade.system.pojo.entity.Tenant;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Date;
import java.util.List;
@ -59,6 +66,8 @@ public class BladeAuthorizationHandler extends AbstractAuthorizationHandler {
private final BladeTenantProperties tenantProperties;
private final OAuth2Properties oAuth2Properties;
private final BladeLockHandler lockHandler;
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 自定义弱密码列表
@ -134,10 +143,36 @@ public class BladeAuthorizationHandler extends AbstractAuthorizationHandler {
public void authSuccessful(OAuth2User user, OAuth2Request request) {
// 处理认证成功,清空错误次数
lockHandler.handleAuthSuccess(user.getTenantId(), user.getAccount());
// 更新 Redis 登录统计
updateUserLoginStats(user);
log.info("用户:{},认证成功", user.getAccount());
}
/**
* 更新用户登录统计信息到 Redis
*/
private void updateUserLoginStats(OAuth2User user) {
// 获取用户ID
String userId = user.getUserId();
// 获取用户名
String username = user.getName();
String key = "user:login:" + userId;
// 获取登录IP
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String loginIp = request.getRemoteAddr();
// 获取部门ID(假设 user 对象提供 getDeptId 方法)
String deptId = user.getDeptId();
// 获取 Redis 操作对象
HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();
// 1. 更新用户名(可选,若用户名可能变更)
hashOps.put(key, "username", username);
// 2. 存储登录IP
hashOps.put(key, "loginIp", loginIp);
// 3. 存储部门ID
hashOps.put(key, "deptId", deptId);
// 4. 更新最后一次登录时间
long lastLoginTime = System.currentTimeMillis();
hashOps.put(key, "lastLoginTime", lastLoginTime);
}
/**
* 认证失败回调
*

@ -30,6 +30,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.AllArgsConstructor;
import org.springblade.core.log.model.LogApi;
import org.springblade.core.log.pojo.dto.UserLoginStatsDTO;
import org.springblade.core.log.pojo.vo.LogApiVO;
import org.springblade.core.log.service.ILogApiService;
import org.springblade.core.log.wrapper.LogApiWrapper;
@ -38,12 +39,13 @@ import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.annotation.IsAdmin;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.*;
/**
* 控制器
@ -77,4 +79,15 @@ public class LogApiController {
return R.data(LogApiWrapper.build().pageVO(pages));
}
@IsAdmin
@GetMapping("/listUserLoginStatus")
public R<List<UserLoginStatsDTO>> getUserLoginStats(
@RequestParam(required = false) String username,
@RequestParam(required = false) String deptId
) {
// 获取所有 user:login:* 键
List<UserLoginStatsDTO> result = logService.getUserLoginStats(username, deptId);
return R.data(result);
}
}

@ -0,0 +1,39 @@
package org.springblade.core.log.pojo.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @author 石玖洲
* @Description
* @create 2026-02-27 14:15
*/
@Data
@AllArgsConstructor
public class UserLoginStatsDTO {
/**
* 用户ID
*/
private String userId;
/**
* 用户名
*/
private String username;
/**
* 登录IP
*/
private String loginIp;
/**
* 部门ID
*/
private String deptId;
/**
* 最后一次登录时间
*/
private Long lastLoginTime;
}

@ -27,6 +27,9 @@ package org.springblade.core.log.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springblade.core.log.model.LogApi;
import org.springblade.core.log.pojo.dto.UserLoginStatsDTO;
import java.util.List;
/**
* 服务类
@ -35,4 +38,11 @@ import org.springblade.core.log.model.LogApi;
*/
public interface ILogApiService extends IService<LogApi> {
/**
* 获取用户登录状态
* @param username 用户名
* @param deptId 部门ID
* @return 用户登录状态列表
*/
List<UserLoginStatsDTO> getUserLoginStats(String username, String deptId);
}

@ -26,11 +26,19 @@
package org.springblade.core.log.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springblade.core.log.controller.LogApiController;
import org.springblade.core.log.mapper.LogApiMapper;
import org.springblade.core.log.model.LogApi;
import org.springblade.core.log.pojo.dto.UserLoginStatsDTO;
import org.springblade.core.log.service.ILogApiService;
import org.springblade.core.tool.api.R;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 服务实现类
*
@ -39,5 +47,39 @@ import org.springframework.stereotype.Service;
@Service
public class LogApiServiceImpl extends ServiceImpl<LogApiMapper, LogApi> implements ILogApiService {
@Resource
private RedisTemplate<String,String> redisTemplate;
@Override
public List<UserLoginStatsDTO> getUserLoginStats(String username, String deptId) {
Set<String> keys = redisTemplate.keys("user:login:*");
if (keys == null || keys.isEmpty()) {
new ArrayList<>();
}
// 获取用户登录信息(带筛选)
List<UserLoginStatsDTO> result = new ArrayList<>();
for (String key : Objects.requireNonNull(keys)) {
HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();
String userId = key.replace("user:login:", "");
String currentUsername = (String) hashOps.get(key, "username");
String currentDeptId = (String) hashOps.get(key, "deptId");
// 过滤条件:根据 username 和 deptId 筛选
boolean matchUsername = username == null || currentUsername != null && currentUsername.contains(username);
boolean matchDept = deptId == null || currentDeptId != null && currentDeptId.equals(deptId);
if (matchUsername && matchDept) {
String loginIp = (String) hashOps.get(key, "loginIp");
Long lastLoginTime = (Long) hashOps.get(key, "lastLoginTime");
if (currentUsername != null && loginIp != null && lastLoginTime != null) {
result.add(new UserLoginStatsDTO(
userId,
currentUsername,
loginIp,
currentDeptId,
lastLoginTime
));
}
}
}
return result;
}
}

Loading…
Cancel
Save