|
|
@@ -2,6 +2,7 @@ package com.xuekairui.user.service;
|
|
|
|
|
|
import com.xuekairui.common.BusinessException;
|
|
|
import com.xuekairui.common.ErrorCode;
|
|
|
+import com.xuekairui.common.RandomUtil;
|
|
|
import com.xuekairui.user.dto.LoginResponse;
|
|
|
import com.xuekairui.user.entity.Admin;
|
|
|
import com.xuekairui.user.mapper.AdminMapper;
|
|
|
@@ -28,6 +29,8 @@ public class AdminAuthService {
|
|
|
private final PasswordUtil passwordUtil;
|
|
|
private final TokenVersionCache tokenVersionCache;
|
|
|
|
|
|
+ private static final int RESET_LEN = 10;
|
|
|
+
|
|
|
/**
|
|
|
* 管理员密码登录(按用户名或手机号)
|
|
|
*/
|
|
|
@@ -90,126 +93,36 @@ public class AdminAuthService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 管理员心跳续期
|
|
|
- */
|
|
|
- public LoginResponse heartbeat(Long adminId, String role) {
|
|
|
- String roleCode = role != null ? role : "ADMIN";
|
|
|
- Long currentVersion = tokenVersionCache.getVersion(adminId, true);
|
|
|
- if (currentVersion == null) {
|
|
|
- Admin admin = adminMapper.selectById(adminId);
|
|
|
- currentVersion = admin != null && admin.getTokenVersion() != null
|
|
|
- ? admin.getTokenVersion() : 0L;
|
|
|
- if (admin != null) {
|
|
|
- tokenVersionCache.putVersion(adminId, true, currentVersion);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- String newAccessToken = jwtUtil.generateAccessToken(adminId, roleCode, currentVersion);
|
|
|
- String newRefreshToken = jwtUtil.generateRefreshToken(adminId);
|
|
|
-
|
|
|
- Admin updateAdmin = new Admin();
|
|
|
- updateAdmin.setId(adminId);
|
|
|
- updateAdmin.setRefreshTokenHash(JwtUtil.hashToken(newRefreshToken));
|
|
|
- updateAdmin.setRefreshTokenStatus("ACTIVE");
|
|
|
- adminMapper.updateById(updateAdmin);
|
|
|
-
|
|
|
- return LoginResponse.builder()
|
|
|
- .userId(adminId)
|
|
|
- .accessToken(newAccessToken)
|
|
|
- .refreshToken(newRefreshToken)
|
|
|
- .expiresIn(jwtUtil.getExpirationInSeconds(roleCode))
|
|
|
- .needBindPhone(false)
|
|
|
- .role(roleCode)
|
|
|
- .build();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Refresh Token 旋转 + 重用检测
|
|
|
+ * 管理员自行修改密码(需验旧密码)
|
|
|
*/
|
|
|
@Transactional
|
|
|
- public LoginResponse refreshToken(String refreshToken) {
|
|
|
- String tokenType = jwtUtil.getTokenType(refreshToken);
|
|
|
- if (!"refresh".equals(tokenType)) {
|
|
|
- throw new BusinessException(ErrorCode.REFRESH_TOKEN_INVALID);
|
|
|
- }
|
|
|
-
|
|
|
- Long adminId = jwtUtil.getUserId(refreshToken);
|
|
|
+ public void setPassword(Long adminId, String oldPassword, String newPassword) {
|
|
|
Admin admin = adminMapper.selectById(adminId);
|
|
|
if (admin == null) {
|
|
|
throw new BusinessException(ErrorCode.USER_NOT_FOUND);
|
|
|
}
|
|
|
-
|
|
|
- String tokenHash = JwtUtil.hashToken(refreshToken);
|
|
|
- String storedHash = admin.getRefreshTokenHash();
|
|
|
- String storedStatus = admin.getRefreshTokenStatus();
|
|
|
-
|
|
|
- // 重用检测
|
|
|
- if (tokenHash.equals(storedHash) && "USED".equals(storedStatus)) {
|
|
|
- log.warn("管理员 {} 的Refresh Token被重用(疑似被盗),踢出所有设备", adminId);
|
|
|
- long newVersion = (admin.getTokenVersion() != null ? admin.getTokenVersion() : 0L) + 1;
|
|
|
- admin.setTokenVersion(newVersion);
|
|
|
- admin.setRefreshTokenHash(null);
|
|
|
- admin.setRefreshTokenStatus(null);
|
|
|
- adminMapper.updateById(admin);
|
|
|
- tokenVersionCache.putVersion(adminId, true, newVersion);
|
|
|
- throw new BusinessException(ErrorCode.TOKEN_KICKED);
|
|
|
- }
|
|
|
-
|
|
|
- if (!tokenHash.equals(storedHash) || !"ACTIVE".equals(storedStatus)) {
|
|
|
- throw new BusinessException(ErrorCode.REFRESH_TOKEN_INVALID);
|
|
|
+ if (admin.getPassword() != null && !admin.getPassword().isEmpty()
|
|
|
+ && oldPassword != null && !passwordUtil.matches(oldPassword, admin.getPassword())) {
|
|
|
+ throw new BusinessException(ErrorCode.OLD_PASSWORD_INCORRECT);
|
|
|
}
|
|
|
-
|
|
|
- // 旋转
|
|
|
- admin.setRefreshTokenStatus("USED");
|
|
|
- String roleCode = admin.getRole() != null ? admin.getRole() : "ADMIN";
|
|
|
- long currentVersion = admin.getTokenVersion() != null ? admin.getTokenVersion() : 0L;
|
|
|
-
|
|
|
- String newAccessToken = jwtUtil.generateAccessToken(admin.getId(), roleCode, currentVersion);
|
|
|
- String newRefreshToken = jwtUtil.generateRefreshToken(admin.getId());
|
|
|
-
|
|
|
- admin.setRefreshTokenHash(JwtUtil.hashToken(newRefreshToken));
|
|
|
- admin.setRefreshTokenStatus("ACTIVE");
|
|
|
+ admin.setPassword(passwordUtil.encode(newPassword));
|
|
|
adminMapper.updateById(admin);
|
|
|
-
|
|
|
- return LoginResponse.builder()
|
|
|
- .userId(admin.getId())
|
|
|
- .accessToken(newAccessToken)
|
|
|
- .refreshToken(newRefreshToken)
|
|
|
- .expiresIn(jwtUtil.getExpirationInSeconds(roleCode))
|
|
|
- .needBindPhone(false)
|
|
|
- .newUser(false)
|
|
|
- .role(roleCode)
|
|
|
- .build();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 修改管理员密码
|
|
|
+ * 重置管理员密码为随机密码,返回明文
|
|
|
*/
|
|
|
@Transactional
|
|
|
- public void setPassword(Long adminId, String oldPassword, String newPassword) {
|
|
|
+ public String resetPassword(Long adminId) {
|
|
|
Admin admin = adminMapper.selectById(adminId);
|
|
|
if (admin == null) {
|
|
|
throw new BusinessException(ErrorCode.USER_NOT_FOUND);
|
|
|
}
|
|
|
- if (admin.getPassword() != null && !admin.getPassword().isEmpty()
|
|
|
- && oldPassword != null && !passwordUtil.matches(oldPassword, admin.getPassword())) {
|
|
|
- throw new BusinessException(ErrorCode.OLD_PASSWORD_INCORRECT);
|
|
|
- }
|
|
|
- admin.setPassword(passwordUtil.encode(newPassword));
|
|
|
+ String rawPwd = RandomUtil.generateCode(RESET_LEN);
|
|
|
+ admin.setPassword(passwordUtil.encode(rawPwd));
|
|
|
adminMapper.updateById(admin);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取管理员信息
|
|
|
- */
|
|
|
- public Admin getById(Long adminId) {
|
|
|
- return adminMapper.selectById(adminId);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 按用户名查询
|
|
|
- */
|
|
|
- public Admin getByUsername(String username) {
|
|
|
- return adminMapper.selectByUsername(username);
|
|
|
+ tokenVersionCache.putVersion(adminId, true,
|
|
|
+ (admin.getTokenVersion() != null ? admin.getTokenVersion() : 0L) + 1);
|
|
|
+ return rawPwd;
|
|
|
}
|
|
|
}
|