This commit is contained in:
2026-08-08 10:11:04 +08:00
parent f3c2bafec8
commit fc14856ea3
64 changed files with 50932 additions and 30 deletions
@@ -55,6 +55,12 @@ public class InternalAccountController {
@PathVariable Long id, @Valid @RequestBody UpdateAccountStatusRequest request) {
verify(token); service.updateStatus(id, request); return ApiResponse.success(null);
}
@PostMapping("/sessions/revoke")
public ApiResponse<Void> revokeSessions(
@RequestHeader(value="X-Internal-Service-Token", required=false) String token,
@Valid @RequestBody RevokeAccountSessionsRequest request) {
verify(token); service.revokeSessions(request.accountIds()); return ApiResponse.success(null);
}
@PutMapping("/{id}/profile")
public ApiResponse<Void> profile(@RequestHeader(value="X-Internal-Service-Token", required=false) String token,
@PathVariable Long id, @Valid @RequestBody UpdateAccountProfileRequest request) {
@@ -2,10 +2,12 @@ package com.baiyue.auth.dto;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;
import jakarta.validation.constraints.Pattern;
import java.time.LocalDateTime;
import java.util.Set;
/** 账号安全及内部账号管理契约。 */
public final class AccountManagementDtos {
@@ -35,6 +37,12 @@ public final class AccountManagementDtos {
}
public record UpdateAccountProfileRequest(@NotBlank @Size(max = 64) String displayName) { }
public record UpdateAccountStatusRequest(@NotBlank String status) { }
public record RevokeAccountSessionsRequest(
@NotEmpty @Size(max = 500) Set<@NotNull Long> accountIds) {
public RevokeAccountSessionsRequest {
accountIds = Set.copyOf(accountIds);
}
}
public record ResetPasswordRequest(@NotBlank @Size(min = 8, max = 64)
@Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d).+$", message = "密码必须同时包含字母和数字") String newPassword,
Boolean forceChangePassword) {
@@ -13,6 +13,7 @@ import com.baiyue.common.audit.BusinessAudit;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
/** 账号生命周期管理,所有密码只以 BCrypt 摘要写入数据库。 */
@Service
@@ -98,6 +99,14 @@ public class AccountManagementService {
bumpVersion(account);
}
@Transactional
@BusinessAudit(event = "ACCOUNT_SESSIONS_REVOKE", resourceType = "ACCOUNT_BATCH",
resourceId = "'RBAC_CHANGE'", description = "RBAC 变更批量撤销账号会话",
captureBefore = false, captureAfter = false)
public void revokeSessions(Set<Long> accountIds) {
accountIds.forEach(accountId -> bumpVersion(required(accountId)));
}
@Transactional
@BusinessAudit(event = "ACCOUNT_PROFILE_CHANGE", resourceType = "ACCOUNT", resourceId = "#accountId",
description = "同步账号显示名称", captureAfter = false)
@@ -118,11 +127,11 @@ public class AccountManagementService {
@BusinessAudit(event = "CUSTOMER_ACCOUNT_ARCHIVE", resourceType = "TENANT", resourceId = "#tenantId",
description = "归档客户并撤销客户账号", captureBefore = false, captureAfter = false)
public void archiveTenant(Long tenantId) {
for (AuthAccount account : accountRepository.findMerchantByTenant(tenantId)) {
for (AuthAccount account : repository.findMerchantByTenant(tenantId)) {
account.setAccountStatus("DISABLED");
account.setPasswordChangeRequired(false);
account.setTokenVersion((account.getTokenVersion() == null ? 0 : account.getTokenVersion()) + 1);
accountRepository.save(account);
repository.save(account);
tokenSessionStore.revokeAll(account.getId());
}
}
@@ -156,7 +156,7 @@ public class AuthService {
@Transactional
@BusinessAudit(event = "CUSTOMER_IMPERSONATION_EXCHANGE", resourceType = "IMPERSONATION",
resourceId = "#code", description = "兑换客户代登录授权码", captureBefore = false, captureAfter = false)
resourceId = "'IMPERSONATION_EXCHANGE'", description = "兑换客户代登录授权码", captureBefore = false, captureAfter = false)
public ImpersonationTokenResponse exchangeImpersonationTicket(String code) {
TokenSessionStore.ImpersonationTicket ticket = tokenSessionStore.consumeImpersonationTicket(code);
if (ticket == null) throw new BizException(ResultCode.UNAUTHORIZED, "代登录授权码无效或已过期");