feat(logs): 添加操作日志功能支持推送和授权模块
- 在JwtAuthFilter中设置认证详情到claims - 为license-service添加LicenseOperationLog相关实体、仓库和服务 - 为push-service添加PushOperationLog相关实体、仓库和服务 - 在LicenseAdminController中注入并使用操作日志记录授权变更 - 在PushManagementController中注入并使用操作日志记录推送操作 - 更新OperationLogService以支持从JWT claims获取用户信息 - 扩展OperationLogService支持推送和授权操作日志查询 - 在前端OperationLogView中添加推送和授权日志选项卡 - 添加LicenseOperationLog和PushOperationLog接口定义 - 实现推送和授权日志的数据加载和分页功能 - 添加操作类型和资源类型的标签映射支持
这个提交包含在:
父节点
f9ad40cb98
当前提交
73dd4814f2
@ -37,6 +37,7 @@ public class JwtAuthFilter extends OncePerRequestFilter {
|
|||||||
: List.of();
|
: List.of();
|
||||||
UsernamePasswordAuthenticationToken auth =
|
UsernamePasswordAuthenticationToken auth =
|
||||||
new UsernamePasswordAuthenticationToken(subject, null, authorities);
|
new UsernamePasswordAuthenticationToken(subject, null, authorities);
|
||||||
|
auth.setDetails(claims);
|
||||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import com.xuqm.license.entity.AppLicenseEntity;
|
|||||||
import com.xuqm.license.entity.DeviceEntity;
|
import com.xuqm.license.entity.DeviceEntity;
|
||||||
import com.xuqm.license.service.AppLicenseService;
|
import com.xuqm.license.service.AppLicenseService;
|
||||||
import com.xuqm.license.service.DeviceService;
|
import com.xuqm.license.service.DeviceService;
|
||||||
|
import com.xuqm.license.service.LicenseOperationLogService;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@ -17,10 +18,13 @@ public class LicenseAdminController {
|
|||||||
|
|
||||||
private final AppLicenseService appLicenseService;
|
private final AppLicenseService appLicenseService;
|
||||||
private final DeviceService deviceService;
|
private final DeviceService deviceService;
|
||||||
|
private final LicenseOperationLogService opLogService;
|
||||||
|
|
||||||
public LicenseAdminController(AppLicenseService appLicenseService, DeviceService deviceService) {
|
public LicenseAdminController(AppLicenseService appLicenseService, DeviceService deviceService,
|
||||||
|
LicenseOperationLogService opLogService) {
|
||||||
this.appLicenseService = appLicenseService;
|
this.appLicenseService = appLicenseService;
|
||||||
this.deviceService = deviceService;
|
this.deviceService = deviceService;
|
||||||
|
this.opLogService = opLogService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/apps/{appKey}")
|
@GetMapping("/apps/{appKey}")
|
||||||
@ -52,18 +56,21 @@ public class LicenseAdminController {
|
|||||||
}
|
}
|
||||||
AppLicenseEntity updated = appLicenseService.update(
|
AppLicenseEntity updated = appLicenseService.update(
|
||||||
appKey, null, req.maxDevices(), newExpiresAt, clearExpiresAt, req.isActive(), req.remark(), null, null, null);
|
appKey, null, req.maxDevices(), newExpiresAt, clearExpiresAt, req.isActive(), req.remark(), null, null, null);
|
||||||
|
opLogService.record(appKey, "UPDATE_LICENSE", "LICENSE", appKey, "更新 " + appKey + " 的授权配置");
|
||||||
return ResponseEntity.ok(ApiResponse.success(updated));
|
return ResponseEntity.ok(ApiResponse.success(updated));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/devices/{id}")
|
@DeleteMapping("/devices/{id}")
|
||||||
public ResponseEntity<ApiResponse<Void>> revokeDevice(@PathVariable String id) {
|
public ResponseEntity<ApiResponse<Void>> revokeDevice(@PathVariable String id) {
|
||||||
deviceService.revoke(id);
|
deviceService.revoke(id);
|
||||||
|
opLogService.record(null, "REVOKE_DEVICE", "DEVICE", id, "吊销设备 " + id + " 的授权");
|
||||||
return ResponseEntity.ok(ApiResponse.ok());
|
return ResponseEntity.ok(ApiResponse.ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/devices/{id}/reactivate")
|
@PutMapping("/devices/{id}/reactivate")
|
||||||
public ResponseEntity<ApiResponse<Void>> reactivateDevice(@PathVariable String id) {
|
public ResponseEntity<ApiResponse<Void>> reactivateDevice(@PathVariable String id) {
|
||||||
deviceService.reactivate(id);
|
deviceService.reactivate(id);
|
||||||
|
opLogService.record(null, "REACTIVATE_DEVICE", "DEVICE", id, "重新激活设备 " + id);
|
||||||
return ResponseEntity.ok(ApiResponse.ok());
|
return ResponseEntity.ok(ApiResponse.ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
package com.xuqm.license.controller;
|
||||||
|
|
||||||
|
import com.xuqm.common.model.ApiResponse;
|
||||||
|
import com.xuqm.license.entity.LicenseOperationLogEntity;
|
||||||
|
import com.xuqm.license.service.LicenseOperationLogService;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/license/admin/operation-logs")
|
||||||
|
public class LicenseOperationLogController {
|
||||||
|
|
||||||
|
private final LicenseOperationLogService logService;
|
||||||
|
|
||||||
|
public LicenseOperationLogController(LicenseOperationLogService logService) {
|
||||||
|
this.logService = logService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<ApiResponse<Map<String, Object>>> list(
|
||||||
|
@RequestParam String appKey,
|
||||||
|
@RequestParam(defaultValue = "0") int page,
|
||||||
|
@RequestParam(defaultValue = "20") int size) {
|
||||||
|
Page<LicenseOperationLogEntity> result = logService.list(appKey, page, size);
|
||||||
|
return ResponseEntity.ok(ApiResponse.success(Map.of(
|
||||||
|
"content", result.getContent(),
|
||||||
|
"total", result.getTotalElements(),
|
||||||
|
"totalPages", result.getTotalPages()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
package com.xuqm.license.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Index;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "license_operation_log", indexes = {
|
||||||
|
@Index(name = "idx_license_op_log_app_time", columnList = "appKey,createdAt")
|
||||||
|
})
|
||||||
|
public class LicenseOperationLogEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = 64)
|
||||||
|
private String appKey;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = 128)
|
||||||
|
private String operator;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = 64)
|
||||||
|
private String action;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = 64)
|
||||||
|
private String resourceType;
|
||||||
|
|
||||||
|
@Column(length = 128)
|
||||||
|
private String resourceId;
|
||||||
|
|
||||||
|
@Column(length = 255)
|
||||||
|
private String summary;
|
||||||
|
|
||||||
|
@Column(columnDefinition = "TEXT")
|
||||||
|
private String detailJson;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
public String getId() { return id; }
|
||||||
|
public void setId(String id) { this.id = id; }
|
||||||
|
|
||||||
|
public String getAppKey() { return appKey; }
|
||||||
|
public void setAppKey(String appKey) { this.appKey = appKey; }
|
||||||
|
|
||||||
|
public String getOperator() { return operator; }
|
||||||
|
public void setOperator(String operator) { this.operator = operator; }
|
||||||
|
|
||||||
|
public String getAction() { return action; }
|
||||||
|
public void setAction(String action) { this.action = action; }
|
||||||
|
|
||||||
|
public String getResourceType() { return resourceType; }
|
||||||
|
public void setResourceType(String resourceType) { this.resourceType = resourceType; }
|
||||||
|
|
||||||
|
public String getResourceId() { return resourceId; }
|
||||||
|
public void setResourceId(String resourceId) { this.resourceId = resourceId; }
|
||||||
|
|
||||||
|
public String getSummary() { return summary; }
|
||||||
|
public void setSummary(String summary) { this.summary = summary; }
|
||||||
|
|
||||||
|
public String getDetailJson() { return detailJson; }
|
||||||
|
public void setDetailJson(String detailJson) { this.detailJson = detailJson; }
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.xuqm.license.repository;
|
||||||
|
|
||||||
|
import com.xuqm.license.entity.LicenseOperationLogEntity;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface LicenseOperationLogRepository extends JpaRepository<LicenseOperationLogEntity, String> {
|
||||||
|
Page<LicenseOperationLogEntity> findByAppKeyOrderByCreatedAtDesc(String appKey, Pageable pageable);
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
package com.xuqm.license.service;
|
||||||
|
|
||||||
|
import com.xuqm.license.entity.LicenseOperationLogEntity;
|
||||||
|
import com.xuqm.license.repository.LicenseOperationLogRepository;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class LicenseOperationLogService {
|
||||||
|
|
||||||
|
private final LicenseOperationLogRepository repository;
|
||||||
|
|
||||||
|
public LicenseOperationLogService(LicenseOperationLogRepository repository) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void record(String appKey, String action, String resourceType,
|
||||||
|
String resourceId, String summary) {
|
||||||
|
LicenseOperationLogEntity entity = new LicenseOperationLogEntity();
|
||||||
|
entity.setId(UUID.randomUUID().toString());
|
||||||
|
entity.setAppKey(appKey);
|
||||||
|
entity.setOperator(currentOperator());
|
||||||
|
entity.setAction(action);
|
||||||
|
entity.setResourceType(resourceType);
|
||||||
|
entity.setResourceId(resourceId);
|
||||||
|
entity.setSummary(summary);
|
||||||
|
entity.setCreatedAt(LocalDateTime.now());
|
||||||
|
repository.save(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Page<LicenseOperationLogEntity> list(String appKey, int page, int size) {
|
||||||
|
int safePage = Math.max(page, 0);
|
||||||
|
int safeSize = Math.min(Math.max(size, 1), 200);
|
||||||
|
return repository.findByAppKeyOrderByCreatedAtDesc(appKey, PageRequest.of(safePage, safeSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String currentOperator() {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (auth == null || auth.getName() == null || auth.getName().isBlank()) {
|
||||||
|
return "system";
|
||||||
|
}
|
||||||
|
if (auth.getDetails() instanceof io.jsonwebtoken.Claims claims) {
|
||||||
|
String nickname = claims.get("nickname", String.class);
|
||||||
|
if (nickname != null && !nickname.isBlank()) return nickname;
|
||||||
|
String username = claims.get("username", String.class);
|
||||||
|
if (username != null && !username.isBlank()) return username;
|
||||||
|
}
|
||||||
|
return auth.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,8 @@ import com.xuqm.push.entity.DeviceLoginLogEntity;
|
|||||||
import com.xuqm.push.entity.PushUserEntity;
|
import com.xuqm.push.entity.PushUserEntity;
|
||||||
import com.xuqm.push.service.PushAccountService;
|
import com.xuqm.push.service.PushAccountService;
|
||||||
import com.xuqm.push.service.PushDiagnosticsService;
|
import com.xuqm.push.service.PushDiagnosticsService;
|
||||||
|
import com.xuqm.push.service.PushOperationLogService;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
@ -28,11 +30,14 @@ public class PushManagementController {
|
|||||||
|
|
||||||
private final PushDiagnosticsService diagnosticsService;
|
private final PushDiagnosticsService diagnosticsService;
|
||||||
private final PushAccountService accountService;
|
private final PushAccountService accountService;
|
||||||
|
private final PushOperationLogService opLogService;
|
||||||
|
|
||||||
public PushManagementController(PushDiagnosticsService diagnosticsService,
|
public PushManagementController(PushDiagnosticsService diagnosticsService,
|
||||||
PushAccountService accountService) {
|
PushAccountService accountService,
|
||||||
|
PushOperationLogService opLogService) {
|
||||||
this.diagnosticsService = diagnosticsService;
|
this.diagnosticsService = diagnosticsService;
|
||||||
this.accountService = accountService;
|
this.accountService = accountService;
|
||||||
|
this.opLogService = opLogService;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- user account management ----
|
// ---- user account management ----
|
||||||
@ -68,6 +73,8 @@ public class PushManagementController {
|
|||||||
}
|
}
|
||||||
PushUserEntity updated = accountService.updateAccount(request.appKey(), userId,
|
PushUserEntity updated = accountService.updateAccount(request.appKey(), userId,
|
||||||
request.nickname(), request.avatar(), gender);
|
request.nickname(), request.avatar(), gender);
|
||||||
|
opLogService.record(request.appKey(), "UPDATE_USER", "ACCOUNT", userId,
|
||||||
|
"编辑用户 " + userId + " 的信息", null);
|
||||||
return ResponseEntity.ok(ApiResponse.success(updated));
|
return ResponseEntity.ok(ApiResponse.success(updated));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +88,11 @@ public class PushManagementController {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return ResponseEntity.badRequest().body(ApiResponse.error(400, "无效的状态值,可选:ACTIVE, BANNED"));
|
return ResponseEntity.badRequest().body(ApiResponse.error(400, "无效的状态值,可选:ACTIVE, BANNED"));
|
||||||
}
|
}
|
||||||
return ResponseEntity.ok(ApiResponse.success(accountService.setUserStatus(request.appKey(), userId, status)));
|
PushUserEntity result = accountService.setUserStatus(request.appKey(), userId, status);
|
||||||
|
String statusLabel = status == PushUserEntity.Status.BANNED ? "禁用" : "启用";
|
||||||
|
opLogService.record(request.appKey(), "UPDATE_USER_STATUS", "ACCOUNT", userId,
|
||||||
|
statusLabel + "用户 " + userId, null);
|
||||||
|
return ResponseEntity.ok(ApiResponse.success(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/users/{userId}")
|
@DeleteMapping("/users/{userId}")
|
||||||
@ -89,6 +100,8 @@ public class PushManagementController {
|
|||||||
@PathVariable String userId,
|
@PathVariable String userId,
|
||||||
@RequestParam String appKey) {
|
@RequestParam String appKey) {
|
||||||
accountService.deleteAccount(appKey, userId);
|
accountService.deleteAccount(appKey, userId);
|
||||||
|
opLogService.record(appKey, "DELETE_USER", "ACCOUNT", userId,
|
||||||
|
"删除用户 " + userId, null);
|
||||||
return ResponseEntity.ok(ApiResponse.ok());
|
return ResponseEntity.ok(ApiResponse.ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,6 +117,8 @@ public class PushManagementController {
|
|||||||
}
|
}
|
||||||
PushUserEntity user = accountService.importAccount(request.appKey(), request.userId(),
|
PushUserEntity user = accountService.importAccount(request.appKey(), request.userId(),
|
||||||
request.nickname(), request.avatar(), gender, status);
|
request.nickname(), request.avatar(), gender, status);
|
||||||
|
opLogService.record(request.appKey(), "IMPORT_USER", "ACCOUNT", request.userId(),
|
||||||
|
"导入用户 " + request.userId(), null);
|
||||||
return ResponseEntity.ok(ApiResponse.success(user));
|
return ResponseEntity.ok(ApiResponse.success(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,6 +154,8 @@ public class PushManagementController {
|
|||||||
request.title(),
|
request.title(),
|
||||||
request.body(),
|
request.body(),
|
||||||
request.payload());
|
request.payload());
|
||||||
|
opLogService.record(request.appKey(), "TEST_PUSH", "PUSH", request.userId(),
|
||||||
|
"向 " + request.userId() + " 发送测试推送", null);
|
||||||
return ResponseEntity.ok(ApiResponse.success(result));
|
return ResponseEntity.ok(ApiResponse.success(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,39 @@
|
|||||||
|
package com.xuqm.push.controller;
|
||||||
|
|
||||||
|
import com.xuqm.common.model.ApiResponse;
|
||||||
|
import com.xuqm.push.entity.PushOperationLogEntity;
|
||||||
|
import com.xuqm.push.service.PushOperationLogService;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/push/admin/operation-logs")
|
||||||
|
@PreAuthorize("hasAnyAuthority('ROLE_OPS', 'ROLE_TENANT', 'ROLE_ADMIN')")
|
||||||
|
public class PushOperationLogController {
|
||||||
|
|
||||||
|
private final PushOperationLogService logService;
|
||||||
|
|
||||||
|
public PushOperationLogController(PushOperationLogService logService) {
|
||||||
|
this.logService = logService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<ApiResponse<Map<String, Object>>> list(
|
||||||
|
@RequestParam String appKey,
|
||||||
|
@RequestParam(defaultValue = "0") int page,
|
||||||
|
@RequestParam(defaultValue = "20") int size) {
|
||||||
|
Page<PushOperationLogEntity> result = logService.list(appKey, page, size);
|
||||||
|
return ResponseEntity.ok(ApiResponse.success(Map.of(
|
||||||
|
"content", result.getContent(),
|
||||||
|
"total", result.getTotalElements(),
|
||||||
|
"totalPages", result.getTotalPages()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
package com.xuqm.push.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Index;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "push_operation_log", indexes = {
|
||||||
|
@Index(name = "idx_push_op_log_app_time", columnList = "appKey,createdAt")
|
||||||
|
})
|
||||||
|
public class PushOperationLogEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = 64)
|
||||||
|
private String appKey;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = 128)
|
||||||
|
private String operator;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = 64)
|
||||||
|
private String action;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = 64)
|
||||||
|
private String resourceType;
|
||||||
|
|
||||||
|
@Column(length = 128)
|
||||||
|
private String resourceId;
|
||||||
|
|
||||||
|
@Column(length = 255)
|
||||||
|
private String summary;
|
||||||
|
|
||||||
|
@Column(columnDefinition = "TEXT")
|
||||||
|
private String detail;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
public String getId() { return id; }
|
||||||
|
public void setId(String id) { this.id = id; }
|
||||||
|
|
||||||
|
public String getAppKey() { return appKey; }
|
||||||
|
public void setAppKey(String appKey) { this.appKey = appKey; }
|
||||||
|
|
||||||
|
public String getOperator() { return operator; }
|
||||||
|
public void setOperator(String operator) { this.operator = operator; }
|
||||||
|
|
||||||
|
public String getAction() { return action; }
|
||||||
|
public void setAction(String action) { this.action = action; }
|
||||||
|
|
||||||
|
public String getResourceType() { return resourceType; }
|
||||||
|
public void setResourceType(String resourceType) { this.resourceType = resourceType; }
|
||||||
|
|
||||||
|
public String getResourceId() { return resourceId; }
|
||||||
|
public void setResourceId(String resourceId) { this.resourceId = resourceId; }
|
||||||
|
|
||||||
|
public String getSummary() { return summary; }
|
||||||
|
public void setSummary(String summary) { this.summary = summary; }
|
||||||
|
|
||||||
|
public String getDetail() { return detail; }
|
||||||
|
public void setDetail(String detail) { this.detail = detail; }
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.xuqm.push.repository;
|
||||||
|
|
||||||
|
import com.xuqm.push.entity.PushOperationLogEntity;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface PushOperationLogRepository extends JpaRepository<PushOperationLogEntity, String> {
|
||||||
|
Page<PushOperationLogEntity> findByAppKeyOrderByCreatedAtDesc(String appKey, Pageable pageable);
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.xuqm.push.service;
|
||||||
|
|
||||||
|
import com.xuqm.push.entity.PushOperationLogEntity;
|
||||||
|
import com.xuqm.push.repository.PushOperationLogRepository;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class PushOperationLogService {
|
||||||
|
|
||||||
|
private final PushOperationLogRepository repository;
|
||||||
|
|
||||||
|
public PushOperationLogService(PushOperationLogRepository repository) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void record(String appKey, String action, String resourceType,
|
||||||
|
String resourceId, String summary, Map<String, Object> detail) {
|
||||||
|
PushOperationLogEntity entity = new PushOperationLogEntity();
|
||||||
|
entity.setId(UUID.randomUUID().toString());
|
||||||
|
entity.setAppKey(appKey);
|
||||||
|
entity.setOperator(currentOperator());
|
||||||
|
entity.setAction(action);
|
||||||
|
entity.setResourceType(resourceType);
|
||||||
|
entity.setResourceId(resourceId);
|
||||||
|
entity.setSummary(summary);
|
||||||
|
entity.setDetail(detail == null ? null : detail.toString());
|
||||||
|
entity.setCreatedAt(LocalDateTime.now());
|
||||||
|
repository.save(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Page<PushOperationLogEntity> list(String appKey, int page, int size) {
|
||||||
|
int safePage = Math.max(page, 0);
|
||||||
|
int safeSize = Math.min(Math.max(size, 1), 200);
|
||||||
|
return repository.findByAppKeyOrderByCreatedAtDesc(appKey, PageRequest.of(safePage, safeSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String currentOperator() {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (auth == null || auth.getName() == null || auth.getName().isBlank()) {
|
||||||
|
return "system";
|
||||||
|
}
|
||||||
|
if (auth.getDetails() instanceof io.jsonwebtoken.Claims claims) {
|
||||||
|
String nickname = claims.get("nickname", String.class);
|
||||||
|
if (nickname != null && !nickname.isBlank()) return nickname;
|
||||||
|
String username = claims.get("username", String.class);
|
||||||
|
if (username != null && !username.isBlank()) return username;
|
||||||
|
}
|
||||||
|
return auth.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -77,6 +77,12 @@ public class OperationLogService {
|
|||||||
if (auth == null || auth.getName() == null || auth.getName().isBlank()) {
|
if (auth == null || auth.getName() == null || auth.getName().isBlank()) {
|
||||||
return "system";
|
return "system";
|
||||||
}
|
}
|
||||||
|
if (auth.getDetails() instanceof io.jsonwebtoken.Claims claims) {
|
||||||
|
String nickname = claims.get("nickname", String.class);
|
||||||
|
if (nickname != null && !nickname.isBlank()) return nickname;
|
||||||
|
String username = claims.get("username", String.class);
|
||||||
|
if (username != null && !username.isBlank()) return username;
|
||||||
|
}
|
||||||
return auth.getName();
|
return auth.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -56,6 +56,12 @@ public class UpdateOperationLogService {
|
|||||||
if (auth == null || auth.getName() == null || auth.getName().isBlank()) {
|
if (auth == null || auth.getName() == null || auth.getName().isBlank()) {
|
||||||
return "system";
|
return "system";
|
||||||
}
|
}
|
||||||
|
if (auth.getDetails() instanceof io.jsonwebtoken.Claims claims) {
|
||||||
|
String nickname = claims.get("nickname", String.class);
|
||||||
|
if (nickname != null && !nickname.isBlank()) return nickname;
|
||||||
|
String username = claims.get("username", String.class);
|
||||||
|
if (username != null && !username.isBlank()) return username;
|
||||||
|
}
|
||||||
return auth.getName();
|
return auth.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户