用户管理与权限系统
# 用户管理与权限系统
# 📖 系统概述
在跨境电商的复杂业务环境中,用户管理与权限系统是整个平台的安全基石。该系统不仅需要管理来自全球不同地区的用户,还要处理多语言、多币种、多时区的复杂场景,同时确保数据安全和隐私合规。
想象一个全球化的电商平台,每天有数百万用户从世界各地访问,他们使用不同的语言、货币和支付方式。系统需要为每个用户提供个性化的体验,同时严格控制访问权限,保护敏感数据。从普通消费者到企业采购员,从客服代表到系统管理员,每个角色都有其特定的权限边界和业务需求。
# 核心功能
- 多租户用户管理:支持B2C消费者、B2B企业用户、平台运营人员等多种用户类型
- 细粒度权限控制:基于RBAC模型的角色权限管理,支持动态权限分配
- 全球化身份认证:支持多种认证方式,包括社交登录、企业SSO、多因素认证
- 数据隐私保护:符合GDPR、CCPA等国际隐私法规的数据处理机制
- 安全审计追踪:完整的用户行为日志和安全事件监控
- 智能风险控制:基于机器学习的异常行为检测和风险评估
# 🏗️ 系统架构设计
graph TB
subgraph "用户管理与权限系统架构"
subgraph "接入层"
A1[Web前端]
A2[移动端APP]
A3[API网关]
A4[第三方集成]
end
subgraph "认证服务层"
B1[身份认证服务]
B2[OAuth2.0服务]
B3[JWT令牌服务]
B4[多因素认证]
B5[社交登录集成]
end
subgraph "权限管理层"
C1[RBAC权限引擎]
C2[动态权限分配]
C3[资源访问控制]
C4[权限缓存服务]
end
subgraph "用户服务层"
D1[用户注册服务]
D2[用户资料管理]
D3[企业用户管理]
D4[用户分组服务]
D5[用户偏好设置]
end
subgraph "安全服务层"
E1[风险评估引擎]
E2[行为分析服务]
E3[安全审计服务]
E4[数据加密服务]
E5[隐私合规服务]
end
subgraph "数据存储层"
F1[(用户数据库)]
F2[(权限数据库)]
F3[(审计日志库)]
F4[(缓存集群)]
F5[(文件存储)]
end
subgraph "外部服务"
G1[邮件服务]
G2[短信服务]
G3[第三方认证]
G4[风控服务]
G5[合规检查]
end
end
A1 --> A3
A2 --> A3
A4 --> A3
A3 --> B1
B1 --> B2
B1 --> B3
B1 --> B4
B1 --> B5
B1 --> C1
C1 --> C2
C1 --> C3
C1 --> C4
B1 --> D1
D1 --> D2
D1 --> D3
D1 --> D4
D1 --> D5
C1 --> E1
E1 --> E2
E1 --> E3
E1 --> E4
E1 --> E5
D1 --> F1
C1 --> F2
E3 --> F3
C4 --> F4
D2 --> F5
B4 --> G1
B4 --> G2
B5 --> G3
E1 --> G4
E5 --> G5
# 💻 核心代码实现
# 1. 用户实体模型
@Entity
@Table(name = "users")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(unique = true, nullable = false)
private String email;
@Column(nullable = false)
private String passwordHash;
@Column(name = "phone_number")
private String phoneNumber;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private UserType userType;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private UserStatus status;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "display_name")
private String displayName;
@Column(name = "avatar_url")
private String avatarUrl;
@Column(name = "preferred_language")
private String preferredLanguage;
@Column(name = "preferred_currency")
private String preferredCurrency;
@Column(name = "time_zone")
private String timeZone;
@Column(name = "country_code")
private String countryCode;
@Column(name = "region_code")
private String regionCode;
@Column(name = "date_of_birth")
private LocalDate dateOfBirth;
@Enumerated(EnumType.STRING)
private Gender gender;
@Column(name = "email_verified")
private Boolean emailVerified = false;
@Column(name = "phone_verified")
private Boolean phoneVerified = false;
@Column(name = "two_factor_enabled")
private Boolean twoFactorEnabled = false;
@Column(name = "last_login_at")
private LocalDateTime lastLoginAt;
@Column(name = "last_login_ip")
private String lastLoginIp;
@Column(name = "login_attempts")
private Integer loginAttempts = 0;
@Column(name = "locked_until")
private LocalDateTime lockedUntil;
@Column(name = "password_changed_at")
private LocalDateTime passwordChangedAt;
@Column(name = "terms_accepted_at")
private LocalDateTime termsAcceptedAt;
@Column(name = "privacy_policy_accepted_at")
private LocalDateTime privacyPolicyAcceptedAt;
@Column(name = "marketing_consent")
private Boolean marketingConsent = false;
@Column(name = "data_processing_consent")
private Boolean dataProcessingConsent = false;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "deleted_at")
private LocalDateTime deletedAt;
// 用户角色关联
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();
// 用户组关联
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "user_groups",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "group_id")
)
private Set<UserGroup> groups = new HashSet<>();
// 用户属性扩展
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<UserAttribute> attributes = new HashSet<>();
// 社交账号关联
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<SocialAccount> socialAccounts = new HashSet<>();
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
/**
* 检查用户是否被锁定
*/
public boolean isLocked() {
return lockedUntil != null && lockedUntil.isAfter(LocalDateTime.now());
}
/**
* 检查用户是否激活
*/
public boolean isActive() {
return status == UserStatus.ACTIVE && !isLocked();
}
/**
* 检查用户是否有指定权限
*/
public boolean hasPermission(String permission) {
return roles.stream()
.flatMap(role -> role.getPermissions().stream())
.anyMatch(perm -> perm.getName().equals(permission));
}
/**
* 检查用户是否有指定角色
*/
public boolean hasRole(String roleName) {
return roles.stream()
.anyMatch(role -> role.getName().equals(roleName));
}
/**
* 获取用户完整显示名称
*/
public String getFullDisplayName() {
if (displayName != null && !displayName.trim().isEmpty()) {
return displayName;
}
if (firstName != null && lastName != null) {
return firstName + " " + lastName;
}
return username;
}
/**
* 增加登录失败次数
*/
public void incrementLoginAttempts() {
this.loginAttempts = (this.loginAttempts == null ? 0 : this.loginAttempts) + 1;
}
/**
* 重置登录失败次数
*/
public void resetLoginAttempts() {
this.loginAttempts = 0;
this.lockedUntil = null;
}
/**
* 锁定用户账户
*/
public void lockAccount(Duration lockDuration) {
this.lockedUntil = LocalDateTime.now().plus(lockDuration);
}
// 其他业务方法省略...
}
// 用户类型枚举
public enum UserType {
CONSUMER, // 普通消费者
BUSINESS, // 企业用户
ADMIN, // 平台管理员
CUSTOMER_SERVICE, // 客服代表
MERCHANT, // 商家用户
SUPPLIER, // 供应商
AFFILIATE // 联盟伙伴
}
// 用户状态枚举
public enum UserStatus {
PENDING, // 待激活
ACTIVE, // 活跃
INACTIVE, // 非活跃
SUSPENDED, // 暂停
BANNED, // 禁用
DELETED // 已删除
}
// 性别枚举
public enum Gender {
MALE,
FEMALE,
OTHER,
PREFER_NOT_TO_SAY
}
# 2. 角色权限模型
@Entity
@Table(name = "roles")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String name;
@Column(name = "display_name")
private String displayName;
private String description;
@Enumerated(EnumType.STRING)
private RoleType type;
@Column(name = "is_system_role")
private Boolean isSystemRole = false;
@Column(name = "is_active")
private Boolean isActive = true;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
// 角色权限关联
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "role_permissions",
joinColumns = @JoinColumn(name = "role_id"),
inverseJoinColumns = @JoinColumn(name = "permission_id")
)
private Set<Permission> permissions = new HashSet<>();
// 角色层级关系
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_role_id")
private Role parentRole;
@OneToMany(mappedBy = "parentRole", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Role> childRoles = new HashSet<>();
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
/**
* 获取所有权限(包括继承的权限)
*/
public Set<Permission> getAllPermissions() {
Set<Permission> allPermissions = new HashSet<>(permissions);
// 递归获取父角色权限
if (parentRole != null) {
allPermissions.addAll(parentRole.getAllPermissions());
}
return allPermissions;
}
/**
* 检查是否有指定权限
*/
public boolean hasPermission(String permissionName) {
return getAllPermissions().stream()
.anyMatch(permission -> permission.getName().equals(permissionName));
}
}
@Entity
@Table(name = "permissions")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Permission {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String name;
@Column(name = "display_name")
private String displayName;
private String description;
@Column(name = "resource_type")
private String resourceType;
@Column(name = "action_type")
private String actionType;
@Enumerated(EnumType.STRING)
private PermissionScope scope;
@Column(name = "is_system_permission")
private Boolean isSystemPermission = false;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
// 权限分组
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "permission_group_id")
private PermissionGroup permissionGroup;
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
// 角色类型枚举
public enum RoleType {
SYSTEM, // 系统角色
BUSINESS, // 业务角色
CUSTOM // 自定义角色
}
// 权限范围枚举
public enum PermissionScope {
GLOBAL, // 全局权限
ORGANIZATION, // 组织权限
DEPARTMENT, // 部门权限
PERSONAL // 个人权限
}
# 3. 用户认证服务
@Service
@Slf4j
public class UserAuthenticationService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private JwtTokenService jwtTokenService;
@Autowired
private TwoFactorAuthService twoFactorAuthService;
@Autowired
private UserSecurityService userSecurityService;
@Autowired
private AuditLogService auditLogService;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final int MAX_LOGIN_ATTEMPTS = 5;
private static final Duration ACCOUNT_LOCK_DURATION = Duration.ofMinutes(30);
/**
* 用户登录认证
*/
@Transactional
public AuthenticationResult authenticate(LoginRequest request) {
String identifier = request.getIdentifier(); // 可以是用户名、邮箱或手机号
String password = request.getPassword();
String clientIp = request.getClientIp();
String userAgent = request.getUserAgent();
// 查找用户
User user = findUserByIdentifier(identifier);
if (user == null) {
auditLogService.logFailedLogin(identifier, clientIp, "用户不存在");
throw new AuthenticationException("用户名或密码错误");
}
// 检查账户状态
validateAccountStatus(user);
// 检查账户是否被锁定
if (user.isLocked()) {
auditLogService.logFailedLogin(identifier, clientIp, "账户被锁定");
throw new AccountLockedException("账户已被锁定,请稍后再试");
}
// 验证密码
if (!passwordEncoder.matches(password, user.getPasswordHash())) {
handleFailedLogin(user, clientIp);
throw new AuthenticationException("用户名或密码错误");
}
// 检查是否需要二次认证
if (user.getTwoFactorEnabled()) {
return handleTwoFactorAuthentication(user, request);
}
// 登录成功处理
return handleSuccessfulLogin(user, clientIp, userAgent);
}
/**
* 二次认证处理
*/
private AuthenticationResult handleTwoFactorAuthentication(User user, LoginRequest request) {
String twoFactorCode = request.getTwoFactorCode();
if (twoFactorCode == null || twoFactorCode.trim().isEmpty()) {
// 发送二次认证码
twoFactorAuthService.sendTwoFactorCode(user);
return AuthenticationResult.builder()
.success(false)
.requiresTwoFactor(true)
.userId(user.getId())
.message("请输入二次认证码")
.build();
}
// 验证二次认证码
if (!twoFactorAuthService.verifyTwoFactorCode(user, twoFactorCode)) {
auditLogService.logFailedTwoFactorAuth(user.getId(), request.getClientIp());
throw new TwoFactorAuthException("二次认证码错误");
}
// 二次认证成功
return handleSuccessfulLogin(user, request.getClientIp(), request.getUserAgent());
}
/**
* 登录成功处理
*/
private AuthenticationResult handleSuccessfulLogin(User user, String clientIp, String userAgent) {
// 重置登录失败次数
user.resetLoginAttempts();
user.setLastLoginAt(LocalDateTime.now());
user.setLastLoginIp(clientIp);
userRepository.save(user);
// 生成JWT令牌
String accessToken = jwtTokenService.generateAccessToken(user);
String refreshToken = jwtTokenService.generateRefreshToken(user);
// 缓存用户会话信息
cacheUserSession(user, accessToken, clientIp, userAgent);
// 记录登录日志
auditLogService.logSuccessfulLogin(user.getId(), clientIp, userAgent);
// 异步执行安全检查
userSecurityService.performSecurityCheck(user, clientIp, userAgent);
return AuthenticationResult.builder()
.success(true)
.userId(user.getId())
.username(user.getUsername())
.accessToken(accessToken)
.refreshToken(refreshToken)
.expiresIn(jwtTokenService.getAccessTokenExpiration())
.userType(user.getUserType())
.roles(user.getRoles().stream()
.map(Role::getName)
.collect(Collectors.toSet()))
.permissions(user.getRoles().stream()
.flatMap(role -> role.getAllPermissions().stream())
.map(Permission::getName)
.collect(Collectors.toSet()))
.build();
}
/**
* 登录失败处理
*/
private void handleFailedLogin(User user, String clientIp) {
user.incrementLoginAttempts();
if (user.getLoginAttempts() >= MAX_LOGIN_ATTEMPTS) {
user.lockAccount(ACCOUNT_LOCK_DURATION);
auditLogService.logAccountLocked(user.getId(), clientIp);
log.warn("用户账户被锁定 - 用户ID: {}, IP: {}", user.getId(), clientIp);
}
userRepository.save(user);
auditLogService.logFailedLogin(user.getUsername(), clientIp, "密码错误");
}
/**
* 根据标识符查找用户
*/
private User findUserByIdentifier(String identifier) {
// 尝试按用户名查找
Optional<User> user = userRepository.findByUsername(identifier);
if (user.isPresent()) {
return user.get();
}
// 尝试按邮箱查找
if (identifier.contains("@")) {
user = userRepository.findByEmail(identifier);
if (user.isPresent()) {
return user.get();
}
}
// 尝试按手机号查找
if (identifier.matches("\\+?[0-9\\s-()]+")) {
user = userRepository.findByPhoneNumber(identifier);
if (user.isPresent()) {
return user.get();
}
}
return null;
}
/**
* 验证账户状态
*/
private void validateAccountStatus(User user) {
switch (user.getStatus()) {
case PENDING:
throw new AccountNotActivatedException("账户尚未激活,请检查邮箱激活链接");
case INACTIVE:
throw new AccountInactiveException("账户已停用,请联系客服");
case SUSPENDED:
throw new AccountSuspendedException("账户已暂停,请联系客服");
case BANNED:
throw new AccountBannedException("账户已被禁用");
case DELETED:
throw new AccountDeletedException("账户已被删除");
case ACTIVE:
// 账户正常,继续处理
break;
default:
throw new AuthenticationException("账户状态异常");
}
}
/**
* 缓存用户会话信息
*/
private void cacheUserSession(User user, String accessToken, String clientIp, String userAgent) {
UserSession session = UserSession.builder()
.userId(user.getId())
.username(user.getUsername())
.accessToken(accessToken)
.clientIp(clientIp)
.userAgent(userAgent)
.loginTime(LocalDateTime.now())
.lastAccessTime(LocalDateTime.now())
.build();
String sessionKey = "user:session:" + user.getId() + ":" + accessToken.substring(0, 8);
redisTemplate.opsForValue().set(sessionKey, session,
Duration.ofSeconds(jwtTokenService.getAccessTokenExpiration()));
}
/**
* 刷新访问令牌
*/
public TokenRefreshResult refreshToken(String refreshToken) {
if (!jwtTokenService.validateRefreshToken(refreshToken)) {
throw new InvalidTokenException("刷新令牌无效或已过期");
}
Long userId = jwtTokenService.getUserIdFromRefreshToken(refreshToken);
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("用户不存在"));
// 检查用户状态
if (!user.isActive()) {
throw new AuthenticationException("用户账户异常");
}
// 生成新的访问令牌
String newAccessToken = jwtTokenService.generateAccessToken(user);
return TokenRefreshResult.builder()
.accessToken(newAccessToken)
.expiresIn(jwtTokenService.getAccessTokenExpiration())
.build();
}
/**
* 用户登出
*/
public void logout(String accessToken) {
// 将令牌加入黑名单
jwtTokenService.blacklistToken(accessToken);
// 清除会话缓存
Long userId = jwtTokenService.getUserIdFromAccessToken(accessToken);
String sessionKey = "user:session:" + userId + ":" + accessToken.substring(0, 8);
redisTemplate.delete(sessionKey);
// 记录登出日志
auditLogService.logLogout(userId);
}
// 其他认证相关方法省略...
}
### 4. 权限管理服务
```java
@Service
@Slf4j
public class PermissionManagementService {
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@Autowired
private PermissionRepository permissionRepository;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private AuditLogService auditLogService;
private static final String PERMISSION_CACHE_PREFIX = "permission:user:";
private static final Duration PERMISSION_CACHE_TTL = Duration.ofMinutes(30);
/**
* 检查用户权限
*/
public boolean hasPermission(Long userId, String permission) {
// 先从缓存获取
Set<String> cachedPermissions = getCachedUserPermissions(userId);
if (cachedPermissions != null) {
return cachedPermissions.contains(permission);
}
// 从数据库获取并缓存
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("用户不存在"));
Set<String> userPermissions = getUserPermissions(user);
cacheUserPermissions(userId, userPermissions);
return userPermissions.contains(permission);
}
/**
* 检查用户是否有指定角色
*/
public boolean hasRole(Long userId, String roleName) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("用户不存在"));
return user.getRoles().stream()
.anyMatch(role -> role.getName().equals(roleName));
}
/**
* 获取用户所有权限
*/
public Set<String> getUserPermissions(User user) {
Set<String> permissions = new HashSet<>();
// 从角色获取权限
for (Role role : user.getRoles()) {
if (role.getIsActive()) {
permissions.addAll(role.getAllPermissions().stream()
.map(Permission::getName)
.collect(Collectors.toSet()));
}
}
// 从用户组获取权限
for (UserGroup group : user.getGroups()) {
if (group.getIsActive()) {
permissions.addAll(group.getPermissions().stream()
.map(Permission::getName)
.collect(Collectors.toSet()));
}
}
return permissions;
}
/**
* 为用户分配角色
*/
@Transactional
public void assignRoleToUser(Long userId, Long roleId, Long operatorId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("用户不存在"));
Role role = roleRepository.findById(roleId)
.orElseThrow(() -> new RoleNotFoundException("角色不存在"));
if (!role.getIsActive()) {
throw new RoleInactiveException("角色已停用");
}
// 检查是否已有该角色
if (user.getRoles().contains(role)) {
throw new RoleAlreadyAssignedException("用户已拥有该角色");
}
user.getRoles().add(role);
userRepository.save(user);
// 清除权限缓存
clearUserPermissionCache(userId);
// 记录审计日志
auditLogService.logRoleAssignment(userId, roleId, operatorId);
log.info("为用户分配角色 - 用户ID: {}, 角色ID: {}, 操作员ID: {}",
userId, roleId, operatorId);
}
/**
* 移除用户角色
*/
@Transactional
public void removeRoleFromUser(Long userId, Long roleId, Long operatorId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("用户不存在"));
Role role = roleRepository.findById(roleId)
.orElseThrow(() -> new RoleNotFoundException("角色不存在"));
if (!user.getRoles().contains(role)) {
throw new RoleNotAssignedException("用户未拥有该角色");
}
user.getRoles().remove(role);
userRepository.save(user);
// 清除权限缓存
clearUserPermissionCache(userId);
// 记录审计日志
auditLogService.logRoleRemoval(userId, roleId, operatorId);
log.info("移除用户角色 - 用户ID: {}, 角色ID: {}, 操作员ID: {}",
userId, roleId, operatorId);
}
/**
* 创建自定义角色
*/
@Transactional
public Role createCustomRole(CreateRoleRequest request, Long operatorId) {
// 检查角色名是否已存在
if (roleRepository.existsByName(request.getName())) {
throw new RoleAlreadyExistsException("角色名已存在");
}
Role role = Role.builder()
.name(request.getName())
.displayName(request.getDisplayName())
.description(request.getDescription())
.type(RoleType.CUSTOM)
.isSystemRole(false)
.isActive(true)
.build();
role = roleRepository.save(role);
// 分配权限
if (request.getPermissionIds() != null && !request.getPermissionIds().isEmpty()) {
assignPermissionsToRole(role.getId(), request.getPermissionIds(), operatorId);
}
// 记录审计日志
auditLogService.logRoleCreation(role.getId(), operatorId);
log.info("创建自定义角色 - 角色ID: {}, 角色名: {}, 操作员ID: {}",
role.getId(), role.getName(), operatorId);
return role;
}
/**
* 为角色分配权限
*/
@Transactional
public void assignPermissionsToRole(Long roleId, Set<Long> permissionIds, Long operatorId) {
Role role = roleRepository.findById(roleId)
.orElseThrow(() -> new RoleNotFoundException("角色不存在"));
if (role.getIsSystemRole()) {
throw new SystemRoleModificationException("不能修改系统角色");
}
Set<Permission> permissions = permissionRepository.findAllById(permissionIds)
.stream().collect(Collectors.toSet());
if (permissions.size() != permissionIds.size()) {
throw new PermissionNotFoundException("部分权限不存在");
}
role.setPermissions(permissions);
roleRepository.save(role);
// 清除相关用户的权限缓存
clearRoleUsersPermissionCache(roleId);
// 记录审计日志
auditLogService.logPermissionAssignment(roleId, permissionIds, operatorId);
log.info("为角色分配权限 - 角色ID: {}, 权限数量: {}, 操作员ID: {}",
roleId, permissions.size(), operatorId);
}
/**
* 动态权限检查(支持资源级权限)
*/
public boolean hasResourcePermission(Long userId, String resource, String action, String resourceId) {
// 构建完整权限字符串
String fullPermission = String.format("%s:%s", resource, action);
// 检查基础权限
if (!hasPermission(userId, fullPermission)) {
return false;
}
// 检查资源级权限
return checkResourceLevelPermission(userId, resource, action, resourceId);
}
/**
* 检查资源级权限
*/
private boolean checkResourceLevelPermission(Long userId, String resource, String action, String resourceId) {
// 获取用户的资源权限配置
List<ResourcePermission> resourcePermissions = getResourcePermissions(userId, resource);
if (resourcePermissions.isEmpty()) {
// 如果没有特定资源权限配置,则允许访问(基于基础权限)
return true;
}
// 检查是否有对特定资源的权限
return resourcePermissions.stream()
.anyMatch(rp -> rp.getResourceId().equals(resourceId) &&
rp.getActions().contains(action));
}
/**
* 获取用户的资源权限
*/
private List<ResourcePermission> getResourcePermissions(Long userId, String resource) {
// 这里可以从数据库或缓存中获取用户的资源级权限配置
// 简化实现,实际项目中需要根据具体需求设计
return Collections.emptyList();
}
/**
* 缓存用户权限
*/
private void cacheUserPermissions(Long userId, Set<String> permissions) {
String cacheKey = PERMISSION_CACHE_PREFIX + userId;
redisTemplate.opsForValue().set(cacheKey, permissions, PERMISSION_CACHE_TTL);
}
/**
* 获取缓存的用户权限
*/
@SuppressWarnings("unchecked")
private Set<String> getCachedUserPermissions(Long userId) {
String cacheKey = PERMISSION_CACHE_PREFIX + userId;
return (Set<String>) redisTemplate.opsForValue().get(cacheKey);
}
/**
* 清除用户权限缓存
*/
private void clearUserPermissionCache(Long userId) {
String cacheKey = PERMISSION_CACHE_PREFIX + userId;
redisTemplate.delete(cacheKey);
}
/**
* 清除角色相关用户的权限缓存
*/
private void clearRoleUsersPermissionCache(Long roleId) {
List<User> roleUsers = userRepository.findByRolesId(roleId);
for (User user : roleUsers) {
clearUserPermissionCache(user.getId());
}
}
// 其他权限管理方法省略...
}
# 5. 用户注册服务
@Service
@Slf4j
public class UserRegistrationService {
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private EmailVerificationService emailVerificationService;
@Autowired
private SmsVerificationService smsVerificationService;
@Autowired
private UserValidationService userValidationService;
@Autowired
private AuditLogService auditLogService;
@Autowired
private NotificationService notificationService;
/**
* 用户注册
*/
@Transactional
public UserRegistrationResult registerUser(UserRegistrationRequest request) {
// 验证注册请求
validateRegistrationRequest(request);
// 检查用户是否已存在
checkUserExistence(request);
// 创建用户
User user = createUser(request);
// 分配默认角色
assignDefaultRole(user, request.getUserType());
// 保存用户
user = userRepository.save(user);
// 发送验证邮件
if (request.getEmail() != null) {
emailVerificationService.sendVerificationEmail(user);
}
// 发送验证短信
if (request.getPhoneNumber() != null) {
smsVerificationService.sendVerificationSms(user);
}
// 记录注册日志
auditLogService.logUserRegistration(user.getId(), request.getClientIp());
// 发送欢迎通知
notificationService.sendWelcomeNotification(user);
log.info("用户注册成功 - 用户ID: {}, 用户名: {}, 邮箱: {}",
user.getId(), user.getUsername(), user.getEmail());
return UserRegistrationResult.builder()
.success(true)
.userId(user.getId())
.username(user.getUsername())
.email(user.getEmail())
.requiresEmailVerification(!user.getEmailVerified())
.requiresPhoneVerification(!user.getPhoneVerified())
.message("注册成功,请查看邮箱验证链接")
.build();
}
/**
* 企业用户注册
*/
@Transactional
public UserRegistrationResult registerBusinessUser(BusinessUserRegistrationRequest request) {
// 验证企业注册请求
validateBusinessRegistrationRequest(request);
// 检查企业信息
validateBusinessInformation(request.getBusinessInfo());
// 创建企业用户
User user = createBusinessUser(request);
// 创建企业信息
BusinessProfile businessProfile = createBusinessProfile(user, request.getBusinessInfo());
// 分配企业用户角色
assignBusinessRole(user, request.getBusinessType());
// 保存用户
user = userRepository.save(user);
// 企业认证流程
initiateBusinessVerification(user, businessProfile);
// 发送企业注册通知
notificationService.sendBusinessRegistrationNotification(user, businessProfile);
log.info("企业用户注册成功 - 用户ID: {}, 企业名称: {}",
user.getId(), businessProfile.getCompanyName());
return UserRegistrationResult.builder()
.success(true)
.userId(user.getId())
.username(user.getUsername())
.email(user.getEmail())
.requiresBusinessVerification(true)
.message("企业注册成功,请等待企业认证审核")
.build();
}
/**
* 邮箱验证
*/
@Transactional
public EmailVerificationResult verifyEmail(String verificationToken) {
EmailVerification verification = emailVerificationService
.getVerificationByToken(verificationToken);
if (verification == null) {
throw new InvalidVerificationTokenException("验证链接无效或已过期");
}
if (verification.isExpired()) {
throw new VerificationTokenExpiredException("验证链接已过期");
}
if (verification.isUsed()) {
throw new VerificationTokenUsedException("验证链接已使用");
}
// 更新用户邮箱验证状态
User user = verification.getUser();
user.setEmailVerified(true);
userRepository.save(user);
// 标记验证为已使用
verification.markAsUsed();
emailVerificationService.saveVerification(verification);
// 检查是否需要激活账户
if (user.getStatus() == UserStatus.PENDING &&
(!requiresPhoneVerification(user) || user.getPhoneVerified())) {
activateUser(user);
}
// 记录验证日志
auditLogService.logEmailVerification(user.getId());
log.info("邮箱验证成功 - 用户ID: {}, 邮箱: {}", user.getId(), user.getEmail());
return EmailVerificationResult.builder()
.success(true)
.userId(user.getId())
.email(user.getEmail())
.accountActivated(user.getStatus() == UserStatus.ACTIVE)
.build();
}
/**
* 手机号验证
*/
@Transactional
public PhoneVerificationResult verifyPhone(PhoneVerificationRequest request) {
User user = userRepository.findById(request.getUserId())
.orElseThrow(() -> new UserNotFoundException("用户不存在"));
if (!smsVerificationService.verifyCode(user.getPhoneNumber(), request.getVerificationCode())) {
throw new InvalidVerificationCodeException("验证码错误或已过期");
}
// 更新用户手机验证状态
user.setPhoneVerified(true);
userRepository.save(user);
// 检查是否需要激活账户
if (user.getStatus() == UserStatus.PENDING && user.getEmailVerified()) {
activateUser(user);
}
// 记录验证日志
auditLogService.logPhoneVerification(user.getId());
log.info("手机验证成功 - 用户ID: {}, 手机号: {}", user.getId(), user.getPhoneNumber());
return PhoneVerificationResult.builder()
.success(true)
.userId(user.getId())
.phoneNumber(user.getPhoneNumber())
.accountActivated(user.getStatus() == UserStatus.ACTIVE)
.build();
}
/**
* 重新发送验证邮件
*/
public void resendVerificationEmail(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("用户不存在"));
if (user.getEmailVerified()) {
throw new EmailAlreadyVerifiedException("邮箱已验证");
}
// 检查发送频率限制
if (emailVerificationService.isRateLimited(user.getEmail())) {
throw new VerificationRateLimitException("发送过于频繁,请稍后再试");
}
emailVerificationService.sendVerificationEmail(user);
log.info("重新发送验证邮件 - 用户ID: {}, 邮箱: {}", user.getId(), user.getEmail());
}
/**
* 重新发送验证短信
*/
public void resendVerificationSms(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("用户不存在"));
if (user.getPhoneVerified()) {
throw new PhoneAlreadyVerifiedException("手机号已验证");
}
// 检查发送频率限制
if (smsVerificationService.isRateLimited(user.getPhoneNumber())) {
throw new VerificationRateLimitException("发送过于频繁,请稍后再试");
}
smsVerificationService.sendVerificationSms(user);
log.info("重新发送验证短信 - 用户ID: {}, 手机号: {}", user.getId(), user.getPhoneNumber());
}
/**
* 验证注册请求
*/
private void validateRegistrationRequest(UserRegistrationRequest request) {
// 用户名验证
if (!userValidationService.isValidUsername(request.getUsername())) {
throw new InvalidUsernameException("用户名格式不正确");
}
// 邮箱验证
if (request.getEmail() != null && !userValidationService.isValidEmail(request.getEmail())) {
throw new InvalidEmailException("邮箱格式不正确");
}
// 手机号验证
if (request.getPhoneNumber() != null && !userValidationService.isValidPhoneNumber(request.getPhoneNumber())) {
throw new InvalidPhoneNumberException("手机号格式不正确");
}
// 密码强度验证
if (!userValidationService.isStrongPassword(request.getPassword())) {
throw new WeakPasswordException("密码强度不足");
}
// 验证必需的同意条款
if (!request.getTermsAccepted()) {
throw new TermsNotAcceptedException("必须同意服务条款");
}
if (!request.getPrivacyPolicyAccepted()) {
throw new PrivacyPolicyNotAcceptedException("必须同意隐私政策");
}
}
/**
* 检查用户是否已存在
*/
private void checkUserExistence(UserRegistrationRequest request) {
// 检查用户名
if (userRepository.existsByUsername(request.getUsername())) {
throw new UsernameAlreadyExistsException("用户名已存在");
}
// 检查邮箱
if (request.getEmail() != null && userRepository.existsByEmail(request.getEmail())) {
throw new EmailAlreadyExistsException("邮箱已注册");
}
// 检查手机号
if (request.getPhoneNumber() != null && userRepository.existsByPhoneNumber(request.getPhoneNumber())) {
throw new PhoneNumberAlreadyExistsException("手机号已注册");
}
}
/**
* 创建用户
*/
private User createUser(UserRegistrationRequest request) {
return User.builder()
.username(request.getUsername())
.email(request.getEmail())
.phoneNumber(request.getPhoneNumber())
.passwordHash(passwordEncoder.encode(request.getPassword()))
.userType(request.getUserType())
.status(UserStatus.PENDING)
.firstName(request.getFirstName())
.lastName(request.getLastName())
.preferredLanguage(request.getPreferredLanguage())
.preferredCurrency(request.getPreferredCurrency())
.timeZone(request.getTimeZone())
.countryCode(request.getCountryCode())
.regionCode(request.getRegionCode())
.dateOfBirth(request.getDateOfBirth())
.gender(request.getGender())
.emailVerified(false)
.phoneVerified(false)
.twoFactorEnabled(false)
.termsAcceptedAt(LocalDateTime.now())
.privacyPolicyAcceptedAt(LocalDateTime.now())
.marketingConsent(request.getMarketingConsent())
.dataProcessingConsent(true)
.passwordChangedAt(LocalDateTime.now())
.build();
}
/**
* 分配默认角色
*/
private void assignDefaultRole(User user, UserType userType) {
String defaultRoleName = getDefaultRoleName(userType);
Role defaultRole = roleRepository.findByName(defaultRoleName)
.orElseThrow(() -> new RoleNotFoundException("默认角色不存在: " + defaultRoleName));
user.getRoles().add(defaultRole);
}
/**
* 获取默认角色名
*/
private String getDefaultRoleName(UserType userType) {
switch (userType) {
case CONSUMER:
return "ROLE_CONSUMER";
case BUSINESS:
return "ROLE_BUSINESS_USER";
case MERCHANT:
return "ROLE_MERCHANT";
case SUPPLIER:
return "ROLE_SUPPLIER";
case AFFILIATE:
return "ROLE_AFFILIATE";
default:
return "ROLE_USER";
}
}
/**
* 激活用户账户
*/
private void activateUser(User user) {
user.setStatus(UserStatus.ACTIVE);
userRepository.save(user);
// 发送激活通知
notificationService.sendAccountActivationNotification(user);
// 记录激活日志
auditLogService.logAccountActivation(user.getId());
log.info("用户账户已激活 - 用户ID: {}", user.getId());
}
/**
* 检查是否需要手机验证
*/
private boolean requiresPhoneVerification(User user) {
return user.getPhoneNumber() != null && !user.getPhoneNumber().trim().isEmpty();
}
// 其他注册相关方法省略...
}
# 6. 安全服务
@Service
@Slf4j
public class SecurityService {
@Autowired
private UserRepository userRepository;
@Autowired
private SecurityEventRepository securityEventRepository;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private NotificationService notificationService;
@Autowired
private GeoLocationService geoLocationService;
@Autowired
private DeviceFingerprintService deviceFingerprintService;
private static final String LOGIN_ATTEMPT_PREFIX = "login_attempt:";
private static final String SUSPICIOUS_ACTIVITY_PREFIX = "suspicious:";
private static final int MAX_LOGIN_ATTEMPTS = 5;
private static final Duration LOCKOUT_DURATION = Duration.ofMinutes(30);
/**
* 检查登录安全性
*/
public SecurityCheckResult checkLoginSecurity(LoginSecurityRequest request) {
User user = userRepository.findByUsername(request.getUsername())
.orElse(null);
if (user == null) {
// 记录无效用户名尝试
recordSecurityEvent(SecurityEventType.INVALID_USERNAME_ATTEMPT,
null, request.getClientIp(), request.getUserAgent());
return SecurityCheckResult.failed("用户不存在");
}
// 检查账户锁定状态
if (isAccountLocked(user.getId())) {
return SecurityCheckResult.failed("账户已锁定");
}
// 检查登录尝试次数
if (isLoginAttemptsExceeded(user.getId())) {
lockAccount(user.getId());
return SecurityCheckResult.failed("登录尝试次数过多,账户已锁定");
}
// 地理位置检查
LocationCheckResult locationCheck = checkLocationSecurity(user, request.getClientIp());
if (locationCheck.isRisky()) {
recordSecurityEvent(SecurityEventType.SUSPICIOUS_LOCATION,
user.getId(), request.getClientIp(), request.getUserAgent());
}
// 设备指纹检查
DeviceCheckResult deviceCheck = checkDeviceSecurity(user, request);
if (deviceCheck.isNewDevice()) {
recordSecurityEvent(SecurityEventType.NEW_DEVICE_LOGIN,
user.getId(), request.getClientIp(), request.getUserAgent());
}
// 时间模式检查
TimePatternCheckResult timeCheck = checkTimePatternSecurity(user, request.getLoginTime());
if (timeCheck.isUnusual()) {
recordSecurityEvent(SecurityEventType.UNUSUAL_TIME_LOGIN,
user.getId(), request.getClientIp(), request.getUserAgent());
}
// 计算风险评分
int riskScore = calculateRiskScore(locationCheck, deviceCheck, timeCheck);
SecurityCheckResult result = SecurityCheckResult.builder()
.success(true)
.userId(user.getId())
.riskScore(riskScore)
.requiresTwoFactor(riskScore > 70 || user.getTwoFactorEnabled())
.requiresAdditionalVerification(riskScore > 50)
.locationCheck(locationCheck)
.deviceCheck(deviceCheck)
.timeCheck(timeCheck)
.build();
// 如果风险较高,发送安全警告
if (riskScore > 80) {
notificationService.sendSecurityAlert(user, request);
}
return result;
}
/**
* 记录登录尝试
*/
public void recordLoginAttempt(Long userId, boolean success, String clientIp, String userAgent) {
String key = LOGIN_ATTEMPT_PREFIX + userId;
if (success) {
// 登录成功,清除失败记录
redisTemplate.delete(key);
recordSecurityEvent(SecurityEventType.LOGIN_SUCCESS, userId, clientIp, userAgent);
} else {
// 登录失败,增加失败计数
redisTemplate.opsForValue().increment(key);
redisTemplate.expire(key, LOCKOUT_DURATION);
recordSecurityEvent(SecurityEventType.LOGIN_FAILURE, userId, clientIp, userAgent);
}
}
/**
* 检查是否超过登录尝试次数
*/
private boolean isLoginAttemptsExceeded(Long userId) {
String key = LOGIN_ATTEMPT_PREFIX + userId;
Integer attempts = (Integer) redisTemplate.opsForValue().get(key);
return attempts != null && attempts >= MAX_LOGIN_ATTEMPTS;
}
/**
* 锁定账户
*/
private void lockAccount(Long userId) {
User user = userRepository.findById(userId).orElse(null);
if (user != null) {
user.setStatus(UserStatus.LOCKED);
user.setLockedAt(LocalDateTime.now());
userRepository.save(user);
// 发送账户锁定通知
notificationService.sendAccountLockNotification(user);
recordSecurityEvent(SecurityEventType.ACCOUNT_LOCKED, userId, null, null);
log.warn("账户已锁定 - 用户ID: {}", userId);
}
}
/**
* 检查账户是否锁定
*/
private boolean isAccountLocked(Long userId) {
User user = userRepository.findById(userId).orElse(null);
return user != null && user.getStatus() == UserStatus.LOCKED;
}
/**
* 地理位置安全检查
*/
private LocationCheckResult checkLocationSecurity(User user, String clientIp) {
GeoLocation currentLocation = geoLocationService.getLocation(clientIp);
List<GeoLocation> userLocations = getUserHistoricalLocations(user.getId());
boolean isNewCountry = userLocations.stream()
.noneMatch(loc -> loc.getCountryCode().equals(currentLocation.getCountryCode()));
boolean isHighRiskCountry = geoLocationService.isHighRiskCountry(currentLocation.getCountryCode());
double distanceFromUsual = calculateDistanceFromUsualLocations(currentLocation, userLocations);
return LocationCheckResult.builder()
.currentLocation(currentLocation)
.isNewCountry(isNewCountry)
.isHighRiskCountry(isHighRiskCountry)
.distanceFromUsual(distanceFromUsual)
.isRisky(isNewCountry || isHighRiskCountry || distanceFromUsual > 1000)
.build();
}
/**
* 设备安全检查
*/
private DeviceCheckResult checkDeviceSecurity(User user, LoginSecurityRequest request) {
String deviceFingerprint = deviceFingerprintService.generateFingerprint(
request.getUserAgent(), request.getScreenResolution(),
request.getTimeZone(), request.getLanguage());
List<String> userDevices = getUserDeviceFingerprints(user.getId());
boolean isNewDevice = !userDevices.contains(deviceFingerprint);
if (isNewDevice) {
// 保存新设备指纹
saveUserDeviceFingerprint(user.getId(), deviceFingerprint);
}
return DeviceCheckResult.builder()
.deviceFingerprint(deviceFingerprint)
.isNewDevice(isNewDevice)
.isTrustedDevice(userDevices.contains(deviceFingerprint))
.build();
}
/**
* 时间模式安全检查
*/
private TimePatternCheckResult checkTimePatternSecurity(User user, LocalDateTime loginTime) {
List<LocalDateTime> userLoginTimes = getUserHistoricalLoginTimes(user.getId());
// 分析用户常用登录时间段
Map<Integer, Long> hourFrequency = userLoginTimes.stream()
.collect(Collectors.groupingBy(
time -> time.getHour(),
Collectors.counting()));
int currentHour = loginTime.getHour();
long currentHourFrequency = hourFrequency.getOrDefault(currentHour, 0L);
// 判断是否为异常时间
boolean isUnusualTime = currentHourFrequency == 0 && userLoginTimes.size() > 10;
return TimePatternCheckResult.builder()
.loginTime(loginTime)
.isUnusual(isUnusualTime)
.hourFrequency(hourFrequency)
.build();
}
/**
* 计算风险评分
*/
private int calculateRiskScore(LocationCheckResult locationCheck,
DeviceCheckResult deviceCheck,
TimePatternCheckResult timeCheck) {
int score = 0;
// 地理位置风险
if (locationCheck.isNewCountry()) score += 30;
if (locationCheck.isHighRiskCountry()) score += 40;
if (locationCheck.getDistanceFromUsual() > 1000) score += 20;
// 设备风险
if (deviceCheck.isNewDevice()) score += 25;
// 时间模式风险
if (timeCheck.isUnusual()) score += 15;
return Math.min(score, 100);
}
/**
* 记录安全事件
*/
private void recordSecurityEvent(SecurityEventType eventType, Long userId,
String clientIp, String userAgent) {
SecurityEvent event = SecurityEvent.builder()
.eventType(eventType)
.userId(userId)
.clientIp(clientIp)
.userAgent(userAgent)
.timestamp(LocalDateTime.now())
.build();
securityEventRepository.save(event);
log.info("安全事件记录 - 类型: {}, 用户ID: {}, IP: {}",
eventType, userId, clientIp);
}
/**
* 密码安全检查
*/
public PasswordSecurityResult checkPasswordSecurity(String password, User user) {
List<String> issues = new ArrayList<>();
int score = 0;
// 长度检查
if (password.length() < 8) {
issues.add("密码长度至少8位");
} else if (password.length() >= 12) {
score += 25;
} else {
score += 15;
}
// 复杂度检查
if (!password.matches(".*[a-z].*")) {
issues.add("密码必须包含小写字母");
} else {
score += 15;
}
if (!password.matches(".*[A-Z].*")) {
issues.add("密码必须包含大写字母");
} else {
score += 15;
}
if (!password.matches(".*[0-9].*")) {
issues.add("密码必须包含数字");
} else {
score += 15;
}
if (!password.matches(".*[!@#$%^&*()_+\\-=\\[\\]{};':"\\\\|,.<>\\/?].*")) {
issues.add("密码必须包含特殊字符");
} else {
score += 20;
}
// 常见密码检查
if (isCommonPassword(password)) {
issues.add("密码过于常见,请使用更复杂的密码");
score -= 30;
}
// 个人信息检查
if (containsPersonalInfo(password, user)) {
issues.add("密码不能包含个人信息");
score -= 20;
}
score = Math.max(0, Math.min(100, score));
PasswordStrength strength;
if (score >= 80) {
strength = PasswordStrength.STRONG;
} else if (score >= 60) {
strength = PasswordStrength.MEDIUM;
} else {
strength = PasswordStrength.WEAK;
}
return PasswordSecurityResult.builder()
.score(score)
.strength(strength)
.issues(issues)
.isAcceptable(issues.isEmpty() && score >= 60)
.build();
}
/**
* 检查是否为常见密码
*/
private boolean isCommonPassword(String password) {
// 这里可以维护一个常见密码列表
Set<String> commonPasswords = Set.of(
"123456", "password", "123456789", "12345678", "12345",
"1234567", "1234567890", "qwerty", "abc123", "111111"
);
return commonPasswords.contains(password.toLowerCase());
}
/**
* 检查密码是否包含个人信息
*/
private boolean containsPersonalInfo(String password, User user) {
String lowerPassword = password.toLowerCase();
if (user.getUsername() != null &&
lowerPassword.contains(user.getUsername().toLowerCase())) {
return true;
}
if (user.getEmail() != null) {
String emailPrefix = user.getEmail().split("@")[0].toLowerCase();
if (lowerPassword.contains(emailPrefix)) {
return true;
}
}
if (user.getFirstName() != null &&
lowerPassword.contains(user.getFirstName().toLowerCase())) {
return true;
}
if (user.getLastName() != null &&
lowerPassword.contains(user.getLastName().toLowerCase())) {
return true;
}
return false;
}
// 辅助方法
private List<GeoLocation> getUserHistoricalLocations(Long userId) {
// 从数据库获取用户历史登录位置
return Collections.emptyList();
}
private double calculateDistanceFromUsualLocations(GeoLocation current, List<GeoLocation> historical) {
// 计算与常用位置的距离
return 0.0;
}
private List<String> getUserDeviceFingerprints(Long userId) {
// 从数据库获取用户设备指纹
return Collections.emptyList();
}
private void saveUserDeviceFingerprint(Long userId, String fingerprint) {
// 保存用户设备指纹
}
private List<LocalDateTime> getUserHistoricalLoginTimes(Long userId) {
// 从数据库获取用户历史登录时间
return Collections.emptyList();
}
}
# 技术亮点
# 1. 多维度权限控制
- 角色层次化管理:支持角色继承和权限聚合
- 资源级权限:细粒度的资源访问控制
- 动态权限检查:支持运行时权限验证
- 权限缓存优化:Redis缓存提升权限检查性能
# 2. 智能安全防护
- 多因素风险评估:地理位置、设备指纹、时间模式分析
- 自适应安全策略:根据风险等级调整安全要求
- 实时威胁检测:异常行为监控和预警
- 密码安全策略:强密码要求和安全检查
# 3. 全球化用户支持
- 多租户架构:支持不同地区的用户管理
- 本地化适配:多语言、多货币、时区支持
- 合规性保障:GDPR、CCPA等数据保护法规遵循
- 跨境数据处理:安全的国际数据传输
# 性能优化
# 1. 缓存策略
@Configuration
public class UserCacheConfig {
@Bean
public CacheManager userCacheManager() {
RedisCacheManager.Builder builder = RedisCacheManager
.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory())
.cacheDefaults(cacheConfiguration());
return builder.build();
}
private RedisCacheConfiguration cacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
}
# 2. 异步处理
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "userTaskExecutor")
public ThreadPoolTaskExecutor userTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(200);
executor.setThreadNamePrefix("User-Async-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
# 监控与分析
# 1. 用户行为监控
@Component
public class UserMetrics {
private final MeterRegistry meterRegistry;
private final Counter userRegistrationCounter;
private final Counter userLoginCounter;
private final Timer authenticationTimer;
public UserMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.userRegistrationCounter = Counter.builder("user.registration")
.description("用户注册计数")
.register(meterRegistry);
this.userLoginCounter = Counter.builder("user.login")
.description("用户登录计数")
.register(meterRegistry);
this.authenticationTimer = Timer.builder("user.authentication.time")
.description("用户认证耗时")
.register(meterRegistry);
}
public void incrementRegistration() {
userRegistrationCounter.increment();
}
public void incrementLogin() {
userLoginCounter.increment();
}
public Timer.Sample startAuthenticationTimer() {
return Timer.start(meterRegistry);
}
}
# 2. 实时监控面板
@RestController
@RequestMapping("/api/admin/user-dashboard")
public class UserDashboardController {
@Autowired
private UserAnalyticsService userAnalyticsService;
@GetMapping("/metrics")
public ResponseEntity<UserMetricsResponse> getUserMetrics() {
UserMetricsResponse metrics = userAnalyticsService.getUserMetrics();
return ResponseEntity.ok(metrics);
}
@GetMapping("/security-events")
public ResponseEntity<List<SecurityEventSummary>> getSecurityEvents(
@RequestParam(defaultValue = "24") int hours) {
List<SecurityEventSummary> events = userAnalyticsService
.getSecurityEventsSummary(hours);
return ResponseEntity.ok(events);
}
@GetMapping("/user-growth")
public ResponseEntity<UserGrowthData> getUserGrowth(
@RequestParam(defaultValue = "30") int days) {
UserGrowthData growth = userAnalyticsService.getUserGrowthData(days);
return ResponseEntity.ok(growth);
}
}
# 关键要点
# 技术特色
- 企业级安全:多层次安全防护和威胁检测
- 高性能架构:缓存优化和异步处理
- 全球化支持:多租户和本地化适配
- 智能分析:用户行为分析和风险评估
# 业务价值
- 安全可靠:全面的安全防护机制
- 用户体验:便捷的注册和认证流程
- 合规保障:满足国际数据保护要求
- 运营支持:丰富的用户分析和监控功能
# 未来发展
- AI安全防护:机器学习威胁检测
- 生物识别:指纹、面部识别等
- 零信任架构:持续验证和最小权限原则
- 隐私计算:联邦学习和差分隐私