package indi.backend.aspect; import indi.backend.annotation.Permissions; import indi.backend.exception.PermissionsException; import indi.backend.repository.dao.TokenPoolRepository; import indi.backend.repository.dao.UsersRepository; import indi.backend.repository.entity.TokenPool; import indi.backend.repository.entity.Users; import jakarta.servlet.http.HttpServletRequest; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; import java.util.UUID; @Aspect @Component public class PermissionsAspect { @Autowired private HttpServletRequest request; @Autowired private UsersRepository usersRepository; @Autowired private TokenPoolRepository tokenPoolRepository; @Before("@annotation(permissions)") public void before(JoinPoint joinPoint, Permissions permissions) { if (permissions.value() < 0 || permissions.value() > 3) { throw new PermissionsException("方法权限范围越界"); } if (permissions.value() != 0) { String token = request.getHeader("token"); if (token == null || token.isEmpty()) { throw new PermissionsException("传入的令牌为空"); } Users users = findUsers(UUID.fromString(token)); if (users.getPermissionsLevel() < permissions.value()) { throw new PermissionsException("用户权限不足"); } } } private Users findUsers(UUID token) { TokenPool tokenPool = tokenPoolRepository.findById(token).orElseThrow(() -> new PermissionsException("令牌不存在")); Date expiredTime = Date.from(LocalDateTime.now().plusSeconds(3600).atZone(ZoneId.systemDefault()).toInstant()); tokenPool.setExpiredTime(expiredTime); tokenPoolRepository.save(tokenPool); Users users = tokenPool.getUser(); if (!Boolean.TRUE.equals(users.getEnabled())) { throw new RuntimeException("账户【" + users.getAccount() + "】已被禁用"); } if (users.getLockStartTime() != null && users.getLockEndTime() != null) { if (users.getLockEndTime().getTime() > new Date().getTime()) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH时mm分"); throw new RuntimeException("账户【" + users.getAccount() + "】已被锁定,锁定时间为" + sdf.format(users.getLockStartTime()) + "至" + sdf.format(users.getLockEndTime())); } else { users.setLockStartTime(null); users.setLockEndTime(null); } } users.setLastActiveTime(expiredTime); usersRepository.save(users); return users; } } 优化代码
时间: 2025-07-09 15:45:34 浏览: 3
<think>嗯,用户让我优化这个名为PermissionsAspect的切面类代码。首先,我需要仔细阅读代码,理解它的功能。这个切面是用来处理权限验证的,使用了Spring AOP。主要逻辑是在方法执行前检查用户的权限级别,是否满足注解中指定的要求,同时处理令牌的有效性和用户状态。
首先,我会检查代码的结构和可能的改进点。注意到在@Before通知中,权限值的检查是硬编码的范围0到3,这可能会导致维护问题,如果权限级别范围变化,需要修改代码。或许可以将权限范围提取为常量或配置参数,提高灵活性。
然后,权限检查部分,如果权限值不是0,就进行令牌验证。这里可以拆分权限验证的逻辑,使其更模块化。比如将令牌验证和用户状态检查分成不同的方法,提高可读性。
在findUsers方法中,存在一些可能的问题。例如,使用了Date和LocalDateTime的转换,可能有时区处理的问题。另外,令牌的过期时间被设置为当前时间加3600秒,这个硬编码的数字应该提取为常量,方便后续调整。
还有,异常处理部分,抛出了RuntimeException,但最好使用具体的自定义异常,比如PermissionsException,保持异常体系的一致性。此外,用户状态的检查,如是否启用、是否被锁定,这些逻辑可以封装到单独的方法中,增强代码的可维护性。
注意到在更新用户最后活动时间时,使用了tokenPool的expiredTime,这可能不太直观,或许应该直接使用当前时间加上超时时间,或者另一个明确的变量。另外,SimpleDateFormat不是线程安全的,虽然在Spring的Bean中通常是单例的,但这里在方法内部创建可能没问题,不过可以考虑使用Java 8的DateTimeFormatter来替代。
此外,代码中可能存在重复的代码,比如处理用户锁定的时间,可以抽取成方法。还有,在更新tokenPool和users的时候,可能存在数据库操作,可以考虑添加事务管理,确保数据的一致性。
另外,findUsers方法的名字可能不太准确,因为它不仅查找用户,还执行了令牌的续期和用户状态的检查,或许可以重命名为更贴切的名字,如validateAndRefreshToken。
最后,代码的可测试性可能不足,依赖了HttpServletRequest、UsersRepository和TokenPoolRepository,可以考虑通过构造函数注入而不是字段注入,方便单元测试时模拟依赖。
总结下来,优化点包括:提取常量、拆分方法、使用自定义异常、改善日期处理、增强事务管理、提高代码可读性和可维护性,以及改进异常消息的提示信息。</think>我将分步骤为您分析如何优化该权限切面代码,并提出改进方案:
1. **常量提取与配置化**
```java
// 权限范围常量
private static final int MIN_PERMISSION_LEVEL = 0;
private static final int MAX_PERMISSION_LEVEL = 3;
// Token有效期配置(单位:秒)
private static final long TOKEN_EXPIRATION = 3600;
```
2. **异常处理优化**
```java
// 自定义异常统一处理
if (!Boolean.TRUE.equals(users.getEnabled())) {
throw new PermissionsException("账户【" + users.getAccount() + "】已被禁用");
}
```
3. **逻辑拆分**
```java
@Before("@annotation(permissions)")
public void before(JoinPoint joinPoint, Permissions permissions) {
validatePermissionRange(permissions.value());
if (permissions.value() != MIN_PERMISSION_LEVEL) {
validateTokenPermission(permissions.value());
}
}
private void validateTokenPermission(int requiredLevel) {
String token = getValidToken();
Users user = validateUser(UUID.fromString(token));
checkPermissionLevel(user, requiredLevel);
}
```
4. **日期时间处理优化**
```java
// 使用DateTimeFormatter替代SimpleDateFormat
private static final DateTimeFormatter LOCK_TIME_FORMATTER =
DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分");
```
5. **Token续期逻辑改进**
```java
private void refreshTokenExpiration(TokenPool tokenPool) {
LocalDateTime newExpiration = LocalDateTime.now().plusSeconds(TOKEN_EXPIRATION);
tokenPool.setExpiredTime(Date.from(newExpiration.atZone(ZoneId.systemDefault()).toInstant()));
tokenPoolRepository.save(tokenPool);
}
```
6. **用户状态校验封装**
```java
private void validateUserStatus(Users user) {
if (!Boolean.TRUE.equals(user.getEnabled())) {
throw new PermissionsException("账户【" + user.getAccount() + "】已被禁用");
}
if (user.getLockEndTime() != null && user.getLockEndTime().after(new Date())) {
String lockedPeriod = formatLockPeriod(user);
throw new PermissionsException("账户【" + user.getAccount() + "】已被锁定,锁定时间为" + lockedPeriod);
}
}
```
7. **完整优化版本建议**:
```java
@Aspect
@Component
public class PermissionsAspect {
// 常量配置
private static final int MIN_PERMISSION = 0;
private static final int MAX_PERMISSION = 3;
private static final long TOKEN_EXPIRATION_SECONDS = 3600;
private static final DateTimeFormatter TIME_FORMATTER =
DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分");
// 依赖注入...
@Before("@annotation(permissions)")
public void checkPermissions(JoinPoint joinPoint, Permissions permissions) {
int requiredLevel = permissions.value();
validateLevelRange(requiredLevel);
if (requiredLevel != MIN_PERMISSION) {
Users user = validateAndGetUser();
checkPermissionLevel(user, requiredLevel);
}
}
private Users validateAndGetUser() {
String token = getValidTokenFromHeader();
TokenPool tokenPool = validateToken(token);
refreshTokenExpiration(tokenPool);
return validateUser(tokenPool.getUser());
}
private String getValidTokenFromHeader() {
String token = request.getHeader("token");
if (token == null || token.isBlank()) {
throw new PermissionsException("请求头中缺少有效令牌");
}
return token;
}
private TokenPool validateToken(String token) {
return tokenPoolRepository.findById(UUID.fromString(token))
.orElseThrow(() -> new PermissionsException("无效的访问令牌"));
}
private void refreshTokenExpiration(TokenPool tokenPool) {
LocalDateTime expiration = LocalDateTime.now().plusSeconds(TOKEN_EXPIRATION_SECONDS);
tokenPool.setExpiredTime(toDate(expiration));
tokenPoolRepository.save(tokenPool);
}
private Users validateUser(Users user) {
validateUserStatus(user);
updateLastActiveTime(user);
return user;
}
private void validateUserStatus(Users user) {
if (!Boolean.TRUE.equals(user.getEnabled())) {
throw new PermissionsException("账户【" + user.getAccount() + "】已被禁用");
}
checkAccountLockStatus(user);
}
private void checkAccountLockStatus(Users user) {
Date now = new Date();
if (user.getLockEndTime() != null && user.getLockEndTime().after(now)) {
String lockPeriod = formatLockPeriod(user.getLockStartTime(), user.getLockEndTime());
throw new PermissionsException("账户【" + user.getAccount() + "】锁定中,锁定时间:" + lockPeriod);
}
clearExpiredLock(user, now);
}
private String formatLockPeriod(Date start, Date end) {
return start.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
.format(TIME_FORMATTER) + " - " +
end.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
.format(TIME_FORMATTER);
}
private void clearExpiredLock(Users user, Date now) {
if (user.getLockEndTime() != null && user.getLockEndTime().before(now)) {
user.setLockStartTime(null);
user.setLockEndTime(null);
usersRepository.save(user);
}
}
private void updateLastActiveTime(Users user) {
user.setLastActiveTime(toDate(LocalDateTime.now().plusSeconds(TOKEN_EXPIRATION_SECONDS)));
usersRepository.save(user);
}
private Date toDate(LocalDateTime localDateTime) {
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
}
private void validateLevelRange(int level) {
if (level < MIN_PERMISSION || level > MAX_PERMISSION) {
throw new PermissionsException("请求权限级别越界,有效范围:" +
MIN_PERMISSION + "-" + MAX_PERMISSION);
}
}
private void checkPermissionLevel(Users user, int requiredLevel) {
if (user.getPermissionsLevel() < requiredLevel) {
throw new PermissionsException("权限不足,需要级别:" + requiredLevel +
",当前级别:" + user.getPermissionsLevel());
}
}
}
```
**主要优化点说明**:
1. **模块化拆分**:将大型方法拆分为多个单一职责的小方法
2. **异常统一处理**:全部使用PermissionsException保持异常体系一致性
3. **线程安全改进**:使用DateTimeFormatter替代SimpleDateFormat
4. **状态管理优化**:增加锁定状态自动清除逻辑
5. **时效性处理**:统一Token有效期和最后活跃时间的更新逻辑
6. **代码可读性**:通过方法命名提升代码自解释能力
7. **配置集中管理**:将魔法数值提取为常量
8. **校验逻辑增强**:增加令牌有效性校验和空令牌处理
9. **时间处理**:统一日期转换方法
10. **状态更新**:优化账户锁定状态的自动清理机制
建议后续可增加:
1. 令牌黑名单机制
2. 权限变更后的令牌失效机制
3. 动态Token有效期配置
4. 访问频率限制
5. 审计日志记录功能
阅读全文
相关推荐
















