|
@@ -1,8 +1,7 @@
|
|
|
-package cn.iocoder.yudao.userserver.modules.system.service.auth.impl;
|
|
|
+package cn.iocoder.yudao.module.member.service.auth;
|
|
|
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.lang.Assert;
|
|
|
-import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
|
|
|
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
|
|
|
import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginLogTypeEnum;
|
|
|
import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginResultEnum;
|
|
@@ -15,18 +14,18 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
|
|
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
|
|
|
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
|
|
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
|
|
-import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper;
|
|
|
-import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
|
|
|
-import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*;
|
|
|
-import cn.iocoder.yudao.userserver.modules.system.convert.auth.SysAuthConvert;
|
|
|
-import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
|
|
|
-import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
|
|
|
-import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
|
|
|
+import cn.iocoder.yudao.framework.security.core.authentication.MultiUsernamePasswordAuthenticationToken;
|
|
|
+import cn.iocoder.yudao.module.member.controller.app.auth.vo.*;
|
|
|
+import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
|
|
|
+import cn.iocoder.yudao.module.member.dal.dataobject.user.UserDO;
|
|
|
+import cn.iocoder.yudao.module.member.dal.mysql.user.UserMapper;
|
|
|
+import cn.iocoder.yudao.module.member.enums.sms.SysSmsSceneEnum;
|
|
|
+import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService;
|
|
|
+import cn.iocoder.yudao.module.member.service.user.UserService;
|
|
|
import com.google.common.annotations.VisibleForTesting;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import me.zhyd.oauth.model.AuthUser;
|
|
|
import org.springframework.context.annotation.Lazy;
|
|
|
-import org.springframework.data.redis.core.StringRedisTemplate;
|
|
|
import org.springframework.security.authentication.AuthenticationManager;
|
|
|
import org.springframework.security.authentication.BadCredentialsException;
|
|
|
import org.springframework.security.authentication.DisabledException;
|
|
@@ -40,31 +39,28 @@ import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
-import javax.validation.Valid;
|
|
|
import java.util.List;
|
|
|
import java.util.Objects;
|
|
|
|
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
|
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
|
|
-import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.*;
|
|
|
+import static cn.iocoder.yudao.module.member.enums.SysErrorCodeConstants.*;
|
|
|
|
|
|
/**
|
|
|
- * Auth Service 实现类
|
|
|
+ * 会员的认证 Service 接口
|
|
|
*
|
|
|
* @author 芋道源码
|
|
|
*/
|
|
|
@Service
|
|
|
@Slf4j
|
|
|
-public class SysAuthServiceImpl implements SysAuthService {
|
|
|
-
|
|
|
- private static final UserTypeEnum USER_TYPE_ENUM = UserTypeEnum.MEMBER;
|
|
|
+public class AuthServiceImpl implements AuthService {
|
|
|
|
|
|
@Resource
|
|
|
@Lazy // 延迟加载,因为存在相互依赖的问题
|
|
|
private AuthenticationManager authenticationManager;
|
|
|
|
|
|
@Resource
|
|
|
- private MbrUserService userService;
|
|
|
+ private UserService userService;
|
|
|
@Resource
|
|
|
private SysSmsCodeService smsCodeService;
|
|
|
@Resource
|
|
@@ -74,28 +70,24 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|
|
@Resource
|
|
|
private SysSocialCoreService socialService;
|
|
|
|
|
|
- @Resource
|
|
|
- private StringRedisTemplate stringRedisTemplate;
|
|
|
@Resource
|
|
|
private PasswordEncoder passwordEncoder;
|
|
|
@Resource
|
|
|
- private MbrUserMapper userMapper;
|
|
|
-
|
|
|
- private static final UserTypeEnum userTypeEnum = UserTypeEnum.MEMBER;
|
|
|
+ private UserMapper userMapper;
|
|
|
|
|
|
@Override
|
|
|
public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException {
|
|
|
// 获取 username 对应的 SysUserDO
|
|
|
- MbrUserDO user = userService.getUserByMobile(mobile);
|
|
|
+ UserDO user = userService.getUserByMobile(mobile);
|
|
|
if (user == null) {
|
|
|
throw new UsernameNotFoundException(mobile);
|
|
|
}
|
|
|
// 创建 LoginUser 对象
|
|
|
- return SysAuthConvert.INSTANCE.convert(user);
|
|
|
+ return AuthConvert.INSTANCE.convert(user);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public String login(SysAuthLoginReqVO reqVO, String userIp, String userAgent) {
|
|
|
+ public String login(AppAuthLoginReqVO reqVO, String userIp, String userAgent) {
|
|
|
// 使用手机 + 密码,进行登录。
|
|
|
LoginUser loginUser = this.login0(reqVO.getMobile(), reqVO.getPassword());
|
|
|
|
|
@@ -105,80 +97,77 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|
|
|
|
|
@Override
|
|
|
@Transactional
|
|
|
- public String smsLogin(SysAuthSmsLoginReqVO reqVO, String userIp, String userAgent) {
|
|
|
+ public String smsLogin(AppAuthSmsLoginReqVO reqVO, String userIp, String userAgent) {
|
|
|
// 校验验证码
|
|
|
smsCodeService.useSmsCode(reqVO.getMobile(), SysSmsSceneEnum.LOGIN_BY_SMS.getScene(),
|
|
|
reqVO.getCode(), userIp);
|
|
|
|
|
|
// 获得获得注册用户
|
|
|
- MbrUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp);
|
|
|
+ UserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp);
|
|
|
Assert.notNull(user, "获取用户失败,结果为空");
|
|
|
|
|
|
// 执行登陆
|
|
|
this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_SMS, SysLoginResultEnum.SUCCESS);
|
|
|
- LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
|
|
|
+ LoginUser loginUser = AuthConvert.INSTANCE.convert(user);
|
|
|
|
|
|
// 缓存登录用户到 Redis 中,返回 sessionId 编号
|
|
|
return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public String socialLogin(MbrAuthSocialLoginReqVO reqVO, String userIp, String userAgent) {
|
|
|
+ public String socialLogin(AppAuthSocialLoginReqVO reqVO, String userIp, String userAgent) {
|
|
|
// 使用 code 授权码,进行登录
|
|
|
AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState());
|
|
|
org.springframework.util.Assert.notNull(authUser, "授权用户不为空");
|
|
|
|
|
|
// 如果未绑定 SysSocialUserDO 用户,则无法自动登录,进行报错
|
|
|
String unionId = socialService.getAuthUserUnionId(authUser);
|
|
|
- List<SysSocialUserDO> socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, USER_TYPE_ENUM);
|
|
|
+ List<SysSocialUserDO> socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, getUserType());
|
|
|
if (CollUtil.isEmpty(socialUsers)) {
|
|
|
throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
|
|
|
}
|
|
|
|
|
|
// 自动登录
|
|
|
- MbrUserDO user = userService.getUser(socialUsers.get(0).getUserId());
|
|
|
+ UserDO user = userService.getUser(socialUsers.get(0).getUserId());
|
|
|
if (user == null) {
|
|
|
throw exception(USER_NOT_EXISTS);
|
|
|
}
|
|
|
this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_SOCIAL, SysLoginResultEnum.SUCCESS);
|
|
|
|
|
|
// 创建 LoginUser 对象
|
|
|
- LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
|
|
|
+ LoginUser loginUser = AuthConvert.INSTANCE.convert(user);
|
|
|
|
|
|
// 绑定社交用户(更新)
|
|
|
- socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM);
|
|
|
+ socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, getUserType());
|
|
|
|
|
|
// 缓存登录用户到 Redis 中,返回 sessionId 编号
|
|
|
return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public String socialLogin2(MbrAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent) {
|
|
|
+ public String socialLogin2(AppAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent) {
|
|
|
AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState());
|
|
|
org.springframework.util.Assert.notNull(authUser, "授权用户不为空");
|
|
|
|
|
|
// 使用手机号、手机验证码登录
|
|
|
- SysAuthSmsLoginReqVO loginReqVO = SysAuthSmsLoginReqVO
|
|
|
- .builder()
|
|
|
- .mobile(reqVO.getMobile())
|
|
|
- .code(reqVO.getSmsCode())
|
|
|
- .build();
|
|
|
+ AppAuthSmsLoginReqVO loginReqVO = AppAuthSmsLoginReqVO.builder()
|
|
|
+ .mobile(reqVO.getMobile()).code(reqVO.getSmsCode()).build();
|
|
|
String sessionId = this.smsLogin(loginReqVO, userIp, userAgent);
|
|
|
LoginUser loginUser = userSessionCoreService.getLoginUser(sessionId);
|
|
|
|
|
|
// 绑定社交用户(新增)
|
|
|
- socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, USER_TYPE_ENUM);
|
|
|
+ socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, getUserType());
|
|
|
return sessionId;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public void socialBind(Long userId, MbrAuthSocialBindReqVO reqVO) {
|
|
|
+ public void socialBind(Long userId, AppAuthSocialBindReqVO reqVO) {
|
|
|
// 使用 code 授权码,进行登录
|
|
|
AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState());
|
|
|
org.springframework.util.Assert.notNull(authUser, "授权用户不为空");
|
|
|
|
|
|
// 绑定社交用户(新增)
|
|
|
- socialService.bindSocialUser(userId, reqVO.getType(), authUser, USER_TYPE_ENUM);
|
|
|
+ socialService.bindSocialUser(userId, reqVO.getType(), authUser, getUserType());
|
|
|
}
|
|
|
|
|
|
private LoginUser login0(String username, String password) {
|
|
@@ -188,7 +177,8 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|
|
try {
|
|
|
// 调用 Spring Security 的 AuthenticationManager#authenticate(...) 方法,使用账号密码进行认证
|
|
|
// 在其内部,会调用到 loadUserByUsername 方法,获取 User 信息
|
|
|
- authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
|
|
|
+ authentication = authenticationManager.authenticate(new MultiUsernamePasswordAuthenticationToken(
|
|
|
+ username, password, getUserType()));
|
|
|
} catch (BadCredentialsException badCredentialsException) {
|
|
|
this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.BAD_CREDENTIALS);
|
|
|
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
|
|
@@ -208,7 +198,7 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|
|
|
|
|
private void createLoginLog(String mobile, SysLoginLogTypeEnum logTypeEnum, SysLoginResultEnum loginResult) {
|
|
|
// 获得用户
|
|
|
- MbrUserDO user = userService.getUserByMobile(mobile);
|
|
|
+ UserDO user = userService.getUserByMobile(mobile);
|
|
|
// 插入登录日志
|
|
|
SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
|
|
|
reqDTO.setLogType(logTypeEnum.getType());
|
|
@@ -246,10 +236,11 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 重新加载 MbrUserDO 信息
|
|
|
- MbrUserDO user = userService.getUser(loginUser.getId());
|
|
|
+ // 重新加载 UserDO 信息
|
|
|
+ UserDO user = userService.getUser(loginUser.getId());
|
|
|
if (user == null || CommonStatusEnum.DISABLE.getStatus().equals(user.getStatus())) {
|
|
|
- throw exception(AUTH_TOKEN_EXPIRED); // 校验 token 时,用户被禁用的情况下,也认为 token 过期,方便前端跳转到登录界面
|
|
|
+ // 校验 token 时,用户被禁用的情况下,也认为 token 过期,方便前端跳转到登录界面
|
|
|
+ throw exception(AUTH_TOKEN_EXPIRED);
|
|
|
}
|
|
|
|
|
|
// 刷新 LoginUser 缓存
|
|
@@ -258,8 +249,8 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|
|
|
|
|
@Override
|
|
|
public LoginUser mockLogin(Long userId) {
|
|
|
- // 获取用户编号对应的 MbrUserDO
|
|
|
- MbrUserDO user = userService.getUser(userId);
|
|
|
+ // 获取用户编号对应的 UserDO
|
|
|
+ UserDO user = userService.getUser(userId);
|
|
|
if (user == null) {
|
|
|
throw new UsernameNotFoundException(String.valueOf(userId));
|
|
|
}
|
|
@@ -268,7 +259,7 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|
|
this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_MOCK, SysLoginResultEnum.SUCCESS);
|
|
|
|
|
|
// 创建 LoginUser 对象
|
|
|
- return SysAuthConvert.INSTANCE.convert(user);
|
|
|
+ return AuthConvert.INSTANCE.convert(user);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -285,46 +276,35 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public void updatePassword(Long userId, @Valid MbrAuthUpdatePasswordReqVO reqVO) {
|
|
|
+ public UserTypeEnum getUserType() {
|
|
|
+ return UserTypeEnum.MEMBER;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void updatePassword(Long userId, AppAuthUpdatePasswordReqVO reqVO) {
|
|
|
// 检验旧密码
|
|
|
- MbrUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword());
|
|
|
+ UserDO userDO = checkOldPassword(userId, reqVO.getOldPassword());
|
|
|
|
|
|
// 更新用户密码
|
|
|
- // TODO @宋天:不要更新整个对象哈
|
|
|
- userDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
|
|
|
- userMapper.updateById(userDO);
|
|
|
+ UserDO mbrUserDO = UserDO.builder().id(userDO.getId())
|
|
|
+ .password(passwordEncoder.encode(reqVO.getPassword())).build();
|
|
|
+ userMapper.updateById(mbrUserDO);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public void resetPassword(MbrAuthResetPasswordReqVO reqVO) {
|
|
|
- // 根据验证码取出手机号,并查询用户
|
|
|
- String mobile = stringRedisTemplate.opsForValue().get(reqVO.getCode());
|
|
|
- MbrUserDO userDO = userMapper.selectByMobile(mobile);
|
|
|
- if (userDO == null){
|
|
|
- throw exception(USER_NOT_EXISTS);
|
|
|
- }
|
|
|
- // TODO @芋艿 这一步没必要检验验证码与手机是否匹配,因为是根据验证码去redis中查找手机号,然后根据手机号查询用户
|
|
|
- // 也就是说 即便黑客以其他方式将验证码发送到自己手机上,最终还是会根据手机号查询用户然后进行重置密码的操作,不存在安全问题
|
|
|
+ public void resetPassword(AppAuthResetPasswordReqVO reqVO) {
|
|
|
+ // 检验用户是否存在
|
|
|
+ UserDO userDO = checkUserIfExists(reqVO.getMobile());
|
|
|
|
|
|
- // TODO @宋天:这块微信在讨论下哈~~~
|
|
|
-
|
|
|
- // 校验验证码
|
|
|
- smsCodeService.useSmsCode(userDO.getMobile(), SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP());
|
|
|
+ // 使用验证码
|
|
|
+ smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(), reqVO.getCode(),
|
|
|
+ getClientIP());
|
|
|
|
|
|
// 更新密码
|
|
|
- userDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
|
|
|
- userMapper.updateById(userDO);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void checkIfMobileMatchCodeAndDeleteCode(String phone, String code) {
|
|
|
- // 检验用户手机与验证码是否匹配
|
|
|
- String mobile = stringRedisTemplate.opsForValue().get(code);
|
|
|
- if (!phone.equals(mobile)){
|
|
|
- throw exception(USER_CODE_FAILED);
|
|
|
- }
|
|
|
- // 销毁redis中此验证码
|
|
|
- stringRedisTemplate.delete(code);
|
|
|
+ UserDO mbrUserDO = UserDO.builder().build();
|
|
|
+ mbrUserDO.setId(userDO.getId());
|
|
|
+ mbrUserDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
|
|
|
+ userMapper.updateById(mbrUserDO);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -332,11 +312,11 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|
|
*
|
|
|
* @param id 用户 id
|
|
|
* @param oldPassword 旧密码
|
|
|
- * @return MbrUserDO 用户实体
|
|
|
+ * @return MemberUserDO 用户实体
|
|
|
*/
|
|
|
@VisibleForTesting
|
|
|
- public MbrUserDO checkOldPassword(Long id, String oldPassword) {
|
|
|
- MbrUserDO user = userMapper.selectById(id);
|
|
|
+ public UserDO checkOldPassword(Long id, String oldPassword) {
|
|
|
+ UserDO user = userMapper.selectById(id);
|
|
|
if (user == null) {
|
|
|
throw exception(USER_NOT_EXISTS);
|
|
|
}
|
|
@@ -347,12 +327,20 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|
|
return user;
|
|
|
}
|
|
|
|
|
|
+ public UserDO checkUserIfExists(String mobile) {
|
|
|
+ UserDO user = userMapper.selectByMobile(mobile);
|
|
|
+ if (user == null) {
|
|
|
+ throw exception(USER_NOT_EXISTS);
|
|
|
+ }
|
|
|
+ return user;
|
|
|
+ }
|
|
|
+
|
|
|
private void createLogoutLog(Long userId, String username) {
|
|
|
SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
|
|
|
reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType());
|
|
|
reqDTO.setTraceId(TracerUtils.getTraceId());
|
|
|
reqDTO.setUserId(userId);
|
|
|
- reqDTO.setUserType(USER_TYPE_ENUM.getValue());
|
|
|
+ reqDTO.setUserType(getUserType().getValue());
|
|
|
reqDTO.setUsername(username);
|
|
|
reqDTO.setUserAgent(ServletUtils.getUserAgent());
|
|
|
reqDTO.setUserIp(getClientIP());
|