package com.emotion.service.impl; import com.emotion.dto.request.AdminLoginRequest; import com.emotion.dto.response.AdminAuthResponse; import com.emotion.dto.response.AdminInfoResponse; import com.emotion.entity.Admin; import com.emotion.exception.AuthException; import com.emotion.service.AdminAuthService; import com.emotion.service.AdminService; import com.emotion.util.JwtUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletRequest; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.concurrent.TimeUnit; /** * 管理员认证服务实现类 * * @author emotion-museum * @date 2025-10-27 */ @Slf4j @Service public class AdminAuthServiceImpl implements AdminAuthService { @Autowired private AdminService adminService; @Autowired private RedisTemplate redisTemplate; @Autowired private JwtUtil jwtUtil; @Autowired private org.springframework.security.crypto.password.PasswordEncoder passwordEncoder; private static final String ADMIN_TOKEN_PREFIX = "admin_token:"; private static final String ADMIN_REFRESH_TOKEN_PREFIX = "admin_refresh_token:"; private static final int TOKEN_EXPIRE_HOURS = 24; private static final int REFRESH_TOKEN_EXPIRE_DAYS = 7; private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Override public AdminAuthResponse login(AdminLoginRequest request) { Admin admin = adminService.getByAccount(request.getAccount()); if (admin == null) { throw new AuthException("账号或密码错误"); } if (admin.getStatus() != 1) { throw new AuthException("账号已被禁用"); } if (!passwordEncoder.matches(request.getPassword(), admin.getPassword())) { throw new AuthException("账号或密码错误"); } log.info("管理员登录成功: account={}, adminId={}", request.getAccount(), admin.getId()); String accessToken = generateAccessToken(admin); String refreshToken = generateRefreshToken(admin); updateLoginInfo(admin); AdminAuthResponse response = new AdminAuthResponse(); response.setAccessToken(accessToken); response.setRefreshToken(refreshToken); response.setExpiresIn((long) TOKEN_EXPIRE_HOURS * 3600); response.setAdminInfo(convertToAdminInfoResponse(admin)); response.setLoginTime(LocalDateTime.now().format(DATE_TIME_FORMATTER)); return response; } @Override public AdminInfoResponse getCurrentAdminInfo(String adminId) { Admin admin = adminService.getById(adminId); if (admin == null) { throw new AuthException("管理员不存在"); } return convertToAdminInfoResponse(admin); } @Override public boolean logout(HttpServletRequest request) { String authHeader = request.getHeader("Authorization"); if (authHeader != null && authHeader.startsWith("Bearer ")) { String token = authHeader.substring(7); String adminId = jwtUtil.getUserIdFromToken(token); if (adminId != null) { redisTemplate.delete(ADMIN_TOKEN_PREFIX + adminId); log.info("管理员登出成功: adminId={}", adminId); return true; } } return false; } @Override public AdminAuthResponse refreshToken(String refreshToken) { if (!jwtUtil.validateToken(refreshToken)) { throw new AuthException("刷新令牌无效或已过期"); } String adminId = jwtUtil.getUserIdFromToken(refreshToken); String userType = jwtUtil.getUserTypeFromToken(refreshToken); if (!"admin".equals(userType)) { throw new AuthException("无效的刷新令牌"); } String cachedToken = (String) redisTemplate.opsForValue().get(ADMIN_REFRESH_TOKEN_PREFIX + adminId); if (cachedToken == null || !cachedToken.equals(refreshToken)) { throw new AuthException("刷新令牌已失效"); } Admin admin = adminService.getById(adminId); if (admin == null) { throw new AuthException("管理员不存在"); } if (admin.getStatus() != 1) { throw new AuthException("账号已被禁用"); } String newAccessToken = generateAccessToken(admin); String newRefreshToken = generateRefreshToken(admin); AdminAuthResponse response = new AdminAuthResponse(); response.setAccessToken(newAccessToken); response.setRefreshToken(newRefreshToken); response.setExpiresIn((long) TOKEN_EXPIRE_HOURS * 3600); response.setAdminInfo(convertToAdminInfoResponse(admin)); response.setLoginTime(LocalDateTime.now().format(DATE_TIME_FORMATTER)); return response; } @Override public boolean validateToken(HttpServletRequest request) { String authHeader = request.getHeader("Authorization"); if (authHeader == null || !authHeader.startsWith("Bearer ")) { return false; } String token = authHeader.substring(7); if (!jwtUtil.validateToken(token)) { return false; } String userType = jwtUtil.getUserTypeFromToken(token); return "admin".equals(userType); } @Override public String getAdminIdFromToken(String token) { return jwtUtil.getUserIdFromToken(token); } private String generateAccessToken(Admin admin) { String token = jwtUtil.generateToken(admin.getId(), admin.getUsername(), "admin"); redisTemplate.opsForValue().set( ADMIN_TOKEN_PREFIX + admin.getId(), token, TOKEN_EXPIRE_HOURS, TimeUnit.HOURS ); return token; } private String generateRefreshToken(Admin admin) { String token = jwtUtil.generateRefreshToken(admin.getId(), admin.getUsername(), "admin"); redisTemplate.opsForValue().set( ADMIN_REFRESH_TOKEN_PREFIX + admin.getId(), token, REFRESH_TOKEN_EXPIRE_DAYS, TimeUnit.DAYS ); return token; } private void updateLoginInfo(Admin admin) { admin.setLastLoginTime(LocalDateTime.now()); admin.setLoginCount(admin.getLoginCount() == null ? 1 : admin.getLoginCount() + 1); adminService.updateById(admin); } private AdminInfoResponse convertToAdminInfoResponse(Admin admin) { AdminInfoResponse response = new AdminInfoResponse(); BeanUtils.copyProperties(admin, response); return response; } }