mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 10:00:30 +08:00
fix: add userId filter to audit search and login lockout logic
This commit is contained in:
+4
-2
@@ -34,19 +34,21 @@ public class AuditController {
|
|||||||
public PageResponse<AuditEventResponse> list(
|
public PageResponse<AuditEventResponse> list(
|
||||||
@RequestParam(required = false) String entityType,
|
@RequestParam(required = false) String entityType,
|
||||||
@RequestParam(required = false) Long entityId,
|
@RequestParam(required = false) Long entityId,
|
||||||
|
@RequestParam(required = false) String userId,
|
||||||
@RequestParam(value = "page", defaultValue = "0") @Min(0) int page,
|
@RequestParam(value = "page", defaultValue = "0") @Min(0) int page,
|
||||||
@RequestParam(value = "size", defaultValue = "20") @Min(1) @Max(200) int size) {
|
@RequestParam(value = "size", defaultValue = "20") @Min(1) @Max(200) int size) {
|
||||||
return auditService.page(entityType, entityId, page, size);
|
return auditService.page(entityType, entityId, userId, page, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/export")
|
@GetMapping("/export")
|
||||||
public ResponseEntity<Resource> exportAuditEvents(
|
public ResponseEntity<Resource> exportAuditEvents(
|
||||||
@RequestParam(required = false) String entityType,
|
@RequestParam(required = false) String entityType,
|
||||||
@RequestParam(required = false) Long entityId,
|
@RequestParam(required = false) Long entityId,
|
||||||
|
@RequestParam(required = false) String userId,
|
||||||
@RequestParam(required = false) String from,
|
@RequestParam(required = false) String from,
|
||||||
@RequestParam(required = false) String to) {
|
@RequestParam(required = false) String to) {
|
||||||
|
|
||||||
List<AuditEventResponse> events = auditService.searchAuditEvents(entityType, entityId, from, to);
|
List<AuditEventResponse> events = auditService.searchAuditEvents(entityType, entityId, from, to, userId);
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("时间,操作者,动作,实体类型,实体ID,摘要,详情\n");
|
sb.append("时间,操作者,动作,实体类型,实体ID,摘要,详情\n");
|
||||||
|
|||||||
+36
-1
@@ -1,7 +1,10 @@
|
|||||||
package cn.craftlabs.platform.api.auth;
|
package cn.craftlabs.platform.api.auth;
|
||||||
|
|
||||||
|
import cn.craftlabs.platform.api.persistence.auth.PlatformLoginAttempt;
|
||||||
|
import cn.craftlabs.platform.api.persistence.auth.PlatformLoginAttemptMapper;
|
||||||
import cn.craftlabs.platform.api.security.JwtService;
|
import cn.craftlabs.platform.api.security.JwtService;
|
||||||
import cn.craftlabs.platform.api.security.PlatformRoles;
|
import cn.craftlabs.platform.api.security.PlatformRoles;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
@@ -20,10 +23,15 @@ public class AuthController {
|
|||||||
|
|
||||||
private final JwtService jwtService;
|
private final JwtService jwtService;
|
||||||
private final PasswordEncoder passwordEncoder;
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final PlatformLoginAttemptMapper loginAttemptMapper;
|
||||||
|
private final HttpServletRequest request;
|
||||||
|
|
||||||
public AuthController(JwtService jwtService, PasswordEncoder passwordEncoder) {
|
public AuthController(JwtService jwtService, PasswordEncoder passwordEncoder,
|
||||||
|
PlatformLoginAttemptMapper loginAttemptMapper, HttpServletRequest request) {
|
||||||
this.jwtService = jwtService;
|
this.jwtService = jwtService;
|
||||||
this.passwordEncoder = passwordEncoder;
|
this.passwordEncoder = passwordEncoder;
|
||||||
|
this.loginAttemptMapper = loginAttemptMapper;
|
||||||
|
this.request = request;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
@@ -31,6 +39,16 @@ public class AuthController {
|
|||||||
String user = body.getOrDefault("username", "");
|
String user = body.getOrDefault("username", "");
|
||||||
String pass = body.getOrDefault("password", "");
|
String pass = body.getOrDefault("password", "");
|
||||||
|
|
||||||
|
var recentQuery = com.baomidou.mybatisplus.core.toolkit.Wrappers.lambdaQuery(PlatformLoginAttempt.class)
|
||||||
|
.eq(PlatformLoginAttempt::getUsername, user)
|
||||||
|
.eq(PlatformLoginAttempt::getSuccess, false)
|
||||||
|
.ge(PlatformLoginAttempt::getAttemptedAt, java.time.OffsetDateTime.now().minusMinutes(15));
|
||||||
|
long recentFailed = loginAttemptMapper.selectCount(recentQuery);
|
||||||
|
if (recentFailed >= 5) {
|
||||||
|
throw new org.springframework.web.server.ResponseStatusException(
|
||||||
|
org.springframework.http.HttpStatus.TOO_MANY_REQUESTS, "账户已临时锁定,请15分钟后重试");
|
||||||
|
}
|
||||||
|
|
||||||
String role;
|
String role;
|
||||||
String displayName;
|
String displayName;
|
||||||
switch (user.toLowerCase()) {
|
switch (user.toLowerCase()) {
|
||||||
@@ -51,10 +69,22 @@ public class AuthController {
|
|||||||
displayName = "运营账号";
|
displayName = "运营账号";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
PlatformLoginAttempt failedAttempt = new PlatformLoginAttempt();
|
||||||
|
failedAttempt.setUsername(user);
|
||||||
|
failedAttempt.setSuccess(false);
|
||||||
|
failedAttempt.setIpAddress(request.getRemoteAddr());
|
||||||
|
failedAttempt.setAttemptedAt(java.time.OffsetDateTime.now());
|
||||||
|
loginAttemptMapper.insert(failedAttempt);
|
||||||
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "invalid credentials");
|
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "invalid credentials");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pass.equals(user.toLowerCase())) {
|
if (!pass.equals(user.toLowerCase())) {
|
||||||
|
PlatformLoginAttempt failedAttempt = new PlatformLoginAttempt();
|
||||||
|
failedAttempt.setUsername(user);
|
||||||
|
failedAttempt.setSuccess(false);
|
||||||
|
failedAttempt.setIpAddress(request.getRemoteAddr());
|
||||||
|
failedAttempt.setAttemptedAt(java.time.OffsetDateTime.now());
|
||||||
|
loginAttemptMapper.insert(failedAttempt);
|
||||||
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "invalid credentials");
|
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "invalid credentials");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +120,11 @@ public class AuthController {
|
|||||||
result.put("roles", List.of(role));
|
result.put("roles", List.of(role));
|
||||||
result.put("displayName", displayName);
|
result.put("displayName", displayName);
|
||||||
result.put("permissions", permissions);
|
result.put("permissions", permissions);
|
||||||
|
|
||||||
|
var clearQuery = com.baomidou.mybatisplus.core.toolkit.Wrappers.lambdaQuery(PlatformLoginAttempt.class)
|
||||||
|
.eq(PlatformLoginAttempt::getUsername, user);
|
||||||
|
loginAttemptMapper.delete(clearQuery);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-12
@@ -47,10 +47,19 @@ public class AuditService {
|
|||||||
auditEventMapper.insert(e);
|
auditEventMapper.insert(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public List<AuditEventResponse> searchAuditEvents(
|
||||||
|
String entityType, Long entityId, String from, String to, String userId) {
|
||||||
|
LambdaQueryWrapper<PlatformAuditEvent> q = buildQuery(entityType, entityId, from, to, userId);
|
||||||
|
return auditEventMapper.selectList(q).stream()
|
||||||
|
.map(this::toResponse)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public PageResponse<AuditEventResponse> page(
|
public PageResponse<AuditEventResponse> page(
|
||||||
String entityType, Long entityId, int page, int size) {
|
String entityType, Long entityId, String userId, int page, int size) {
|
||||||
LambdaQueryWrapper<PlatformAuditEvent> q = buildQuery(entityType, entityId, null, null);
|
LambdaQueryWrapper<PlatformAuditEvent> q = buildQuery(entityType, entityId, null, null, userId);
|
||||||
Page<PlatformAuditEvent> mpPage = new Page<>(page + 1L, size);
|
Page<PlatformAuditEvent> mpPage = new Page<>(page + 1L, size);
|
||||||
auditEventMapper.selectPage(mpPage, q);
|
auditEventMapper.selectPage(mpPage, q);
|
||||||
List<AuditEventResponse> content =
|
List<AuditEventResponse> content =
|
||||||
@@ -58,17 +67,8 @@ public class AuditService {
|
|||||||
return new PageResponse<>(content, mpPage.getTotal(), page, size);
|
return new PageResponse<>(content, mpPage.getTotal(), page, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
|
||||||
public List<AuditEventResponse> searchAuditEvents(
|
|
||||||
String entityType, Long entityId, String from, String to) {
|
|
||||||
LambdaQueryWrapper<PlatformAuditEvent> q = buildQuery(entityType, entityId, from, to);
|
|
||||||
return auditEventMapper.selectList(q).stream()
|
|
||||||
.map(this::toResponse)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private LambdaQueryWrapper<PlatformAuditEvent> buildQuery(
|
private LambdaQueryWrapper<PlatformAuditEvent> buildQuery(
|
||||||
String entityType, Long entityId, String from, String to) {
|
String entityType, Long entityId, String from, String to, String userId) {
|
||||||
LambdaQueryWrapper<PlatformAuditEvent> q =
|
LambdaQueryWrapper<PlatformAuditEvent> q =
|
||||||
Wrappers.lambdaQuery(PlatformAuditEvent.class)
|
Wrappers.lambdaQuery(PlatformAuditEvent.class)
|
||||||
.orderByDesc(PlatformAuditEvent::getId);
|
.orderByDesc(PlatformAuditEvent::getId);
|
||||||
@@ -84,6 +84,9 @@ public class AuditService {
|
|||||||
if (to != null && !to.isBlank()) {
|
if (to != null && !to.isBlank()) {
|
||||||
q.le(PlatformAuditEvent::getCreatedAt, OffsetDateTime.parse(to + "T23:59:59Z"));
|
q.le(PlatformAuditEvent::getCreatedAt, OffsetDateTime.parse(to + "T23:59:59Z"));
|
||||||
}
|
}
|
||||||
|
if (userId != null && !userId.isBlank()) {
|
||||||
|
q.eq(PlatformAuditEvent::getActorUserId, userId.trim());
|
||||||
|
}
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user