package com.iailab.module.system.service.auth;
|
|
import cn.hutool.core.util.ObjectUtil;
|
import com.iailab.framework.common.enums.CommonStatusEnum;
|
import com.iailab.framework.common.enums.UserTypeEnum;
|
import com.iailab.framework.common.util.monitor.TracerUtils;
|
import com.iailab.framework.common.util.servlet.ServletUtils;
|
import com.iailab.framework.common.util.validation.ValidationUtils;
|
import com.iailab.module.system.api.logger.dto.LoginLogCreateReqDTO;
|
import com.iailab.module.system.api.sms.SmsCodeApi;
|
import com.iailab.module.system.api.social.dto.SocialUserBindReqDTO;
|
import com.iailab.module.system.api.social.dto.SocialUserRespDTO;
|
import com.iailab.module.system.controller.admin.auth.vo.*;
|
import com.iailab.module.system.convert.auth.AuthConvert;
|
import com.iailab.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
import com.iailab.module.system.dal.dataobject.user.AdminUserDO;
|
import com.iailab.module.system.enums.logger.LoginLogTypeEnum;
|
import com.iailab.module.system.enums.logger.LoginResultEnum;
|
import com.iailab.module.system.enums.oauth2.OAuth2ClientConstants;
|
import com.iailab.module.system.enums.sms.SmsSceneEnum;
|
import com.iailab.module.system.service.logger.LoginLogService;
|
import com.iailab.module.system.service.member.MemberService;
|
import com.iailab.module.system.service.oauth2.OAuth2TokenService;
|
import com.iailab.module.system.service.social.SocialUserService;
|
import com.iailab.module.system.service.user.AdminUserService;
|
import com.google.common.annotations.VisibleForTesting;
|
import com.xingyuv.captcha.model.common.ResponseModel;
|
import com.xingyuv.captcha.model.vo.CaptchaVO;
|
import com.xingyuv.captcha.service.CaptchaService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Service;
|
|
import javax.annotation.Resource;
|
import javax.validation.Validator;
|
import java.util.Objects;
|
|
import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static com.iailab.framework.common.util.servlet.ServletUtils.getClientIP;
|
import static com.iailab.module.system.enums.ErrorCodeConstants.*;
|
|
/**
|
* Auth Service 实现类
|
*
|
* @author iailab
|
*/
|
@Service
|
@Slf4j
|
public class AdminAuthServiceImpl implements AdminAuthService {
|
|
@Resource
|
private AdminUserService userService;
|
@Resource
|
private LoginLogService loginLogService;
|
@Resource
|
private OAuth2TokenService oauth2TokenService;
|
@Resource
|
private SocialUserService socialUserService;
|
@Resource
|
private MemberService memberService;
|
@Resource
|
private Validator validator;
|
@Resource
|
private CaptchaService captchaService;
|
@Resource
|
private SmsCodeApi smsCodeApi;
|
|
/**
|
* 验证码的开关,默认为 true
|
*/
|
@Value("${iailab.captcha.enable:true}")
|
private Boolean captchaEnable;
|
|
@Override
|
public AdminUserDO authenticate(String username, String password) {
|
final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_USERNAME;
|
// 校验账号是否存在
|
AdminUserDO user = userService.getUserByUsername(username);
|
if (user == null) {
|
createLoginLog(null, username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
|
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
|
}
|
if (!userService.isPasswordMatch(password, user.getPassword())) {
|
createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
|
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
|
}
|
// 校验是否禁用
|
if (CommonStatusEnum.isDisable(user.getStatus())) {
|
createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.USER_DISABLED);
|
throw exception(AUTH_LOGIN_USER_DISABLED);
|
}
|
return user;
|
}
|
|
@Override
|
public AuthLoginRespVO login(AuthLoginReqVO reqVO) {
|
// 校验验证码
|
validateCaptcha(reqVO);
|
|
// 使用账号密码,进行登录
|
AdminUserDO user = authenticate(reqVO.getUsername(), reqVO.getPassword());
|
|
// 如果 socialType 非空,说明需要绑定社交用户
|
if (reqVO.getSocialType() != null) {
|
socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
|
reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()));
|
}
|
// 创建 Token 令牌,记录登录日志
|
return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
|
}
|
|
@Override
|
public void sendSmsCode(AuthSmsSendReqVO reqVO) {
|
// 登录场景,验证是否存在
|
if (userService.getUserByMobile(reqVO.getMobile()) == null) {
|
throw exception(AUTH_MOBILE_NOT_EXISTS);
|
}
|
// 发送验证码
|
smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP()));
|
}
|
|
@Override
|
public AuthLoginRespVO smsLogin(AuthSmsLoginReqVO reqVO) {
|
// 校验验证码
|
smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.ADMIN_MEMBER_LOGIN.getScene(), getClientIP())).getCheckedData();
|
|
// 获得用户信息
|
AdminUserDO user = userService.getUserByMobile(reqVO.getMobile());
|
if (user == null) {
|
throw exception(USER_NOT_EXISTS);
|
}
|
|
// 创建 Token 令牌,记录登录日志
|
return createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE);
|
}
|
|
private void createLoginLog(Long userId, String username,
|
LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) {
|
// 插入登录日志
|
LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
|
reqDTO.setLogType(logTypeEnum.getType());
|
reqDTO.setTraceId(TracerUtils.getTraceId());
|
reqDTO.setUserId(userId);
|
reqDTO.setUserType(getUserType().getValue());
|
reqDTO.setUsername(username);
|
reqDTO.setUserAgent(ServletUtils.getUserAgent());
|
reqDTO.setUserIp(ServletUtils.getClientIP());
|
reqDTO.setResult(loginResult.getResult());
|
loginLogService.createLoginLog(reqDTO);
|
// 更新最后登录时间
|
if (userId != null && Objects.equals(LoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) {
|
userService.updateUserLogin(userId, ServletUtils.getClientIP());
|
}
|
}
|
|
@Override
|
public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) {
|
// 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
|
SocialUserRespDTO socialUser = socialUserService.getSocialUserByCode(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
|
reqVO.getCode(), reqVO.getState());
|
if (socialUser == null || socialUser.getUserId() == null) {
|
throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
|
}
|
|
// 获得用户
|
AdminUserDO user = userService.getUser(socialUser.getUserId());
|
if (user == null) {
|
throw exception(USER_NOT_EXISTS);
|
}
|
|
// 创建 Token 令牌,记录登录日志
|
return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
|
}
|
|
@VisibleForTesting
|
void validateCaptcha(AuthLoginReqVO reqVO) {
|
// 如果验证码关闭,则不进行校验
|
if (!captchaEnable) {
|
return;
|
}
|
// 校验验证码
|
ValidationUtils.validate(validator, reqVO, AuthLoginReqVO.CodeEnableGroup.class);
|
CaptchaVO captchaVO = new CaptchaVO();
|
captchaVO.setCaptchaVerification(reqVO.getCaptchaVerification());
|
ResponseModel response = captchaService.verification(captchaVO);
|
// 验证不通过
|
if (!response.isSuccess()) {
|
// 创建登录失败日志(验证码不正确)
|
createLoginLog(null, reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, LoginResultEnum.CAPTCHA_CODE_ERROR);
|
throw exception(AUTH_LOGIN_CAPTCHA_CODE_ERROR, response.getRepMsg());
|
}
|
}
|
|
private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) {
|
// 插入登陆日志
|
createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS);
|
// 创建访问令牌
|
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(),
|
OAuth2ClientConstants.CLIENT_ID_DEFAULT, null);
|
// 构建返回结果
|
return AuthConvert.INSTANCE.convert(accessTokenDO);
|
}
|
|
@Override
|
public AuthLoginRespVO refreshToken(String refreshToken) {
|
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT);
|
return AuthConvert.INSTANCE.convert(accessTokenDO);
|
}
|
|
@Override
|
public void logout(String token, Integer logType) {
|
// 删除访问令牌
|
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.removeAccessToken(token);
|
if (accessTokenDO == null) {
|
return;
|
}
|
// 删除成功,则记录登出日志
|
createLogoutLog(accessTokenDO.getUserId(), accessTokenDO.getUserType(), logType);
|
}
|
|
private void createLogoutLog(Long userId, Integer userType, Integer logType) {
|
LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
|
reqDTO.setLogType(logType);
|
reqDTO.setTraceId(TracerUtils.getTraceId());
|
reqDTO.setUserId(userId);
|
reqDTO.setUserType(userType);
|
if (ObjectUtil.equal(getUserType().getValue(), userType)) {
|
reqDTO.setUsername(getUsername(userId));
|
} else {
|
reqDTO.setUsername(memberService.getMemberUserMobile(userId));
|
}
|
reqDTO.setUserAgent(ServletUtils.getUserAgent());
|
reqDTO.setUserIp(ServletUtils.getClientIP());
|
reqDTO.setResult(LoginResultEnum.SUCCESS.getResult());
|
loginLogService.createLoginLog(reqDTO);
|
}
|
|
private String getUsername(Long userId) {
|
if (userId == null) {
|
return null;
|
}
|
AdminUserDO user = userService.getUser(userId);
|
return user != null ? user.getUsername() : null;
|
}
|
|
private UserTypeEnum getUserType() {
|
return UserTypeEnum.ADMIN;
|
}
|
|
}
|