Browse Source

小程序登录优化

master
DX 1 week ago
parent
commit
e8a5f2819a
  1. 6
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
  2. 49
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
  3. 129
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
  4. 42
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java

6
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java

@ -119,6 +119,10 @@ public interface ErrorCodeConstants {
// ========== 社交用户 1-002-018-000 ========== // ========== 社交用户 1-002-018-000 ==========
ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "社交授权失败,原因是:{}"); ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "社交授权失败,原因是:{}");
ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "社交授权失败,找不到对应的用户"); ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "社交授权失败,找不到对应的用户");
ErrorCode SOCIAL_USER_CODE_EXPIRED = new ErrorCode(1_002_018_002, "微信授权码已过期,请重新授权");
ErrorCode SOCIAL_USER_CODE_INVALID = new ErrorCode(1_002_018_003, "微信授权码无效或已被使用");
ErrorCode SOCIAL_USER_NETWORK_ERROR = new ErrorCode(1_002_018_005, "微信服务器连接失败,请稍后重试");
ErrorCode SOCIAL_USER_OPENID_MISMATCH = new ErrorCode(1_002_018_006, "用户身份验证失败,请重新登录");
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_200, "获得手机号失败"); ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_200, "获得手机号失败");
ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR = new ErrorCode(1_002_018_201, "获得小程序码失败"); ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR = new ErrorCode(1_002_018_201, "获得小程序码失败");
@ -128,8 +132,6 @@ public interface ErrorCodeConstants {
ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_211, "社交客户端已存在配置"); ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_211, "社交客户端已存在配置");
ErrorCode SOCIAL_CLIENT_CODE_EXISTS = new ErrorCode(1_002_018_212, "社交客户端CODE不存在"); ErrorCode SOCIAL_CLIENT_CODE_EXISTS = new ErrorCode(1_002_018_212, "社交客户端CODE不存在");
// ========== OAuth2 客户端 1-002-020-000 ========= // ========== OAuth2 客户端 1-002-020-000 =========
ErrorCode OAUTH2_CLIENT_NOT_EXISTS = new ErrorCode(1_002_020_000, "OAuth2 客户端不存在"); ErrorCode OAUTH2_CLIENT_NOT_EXISTS = new ErrorCode(1_002_020_000, "OAuth2 客户端不存在");
ErrorCode OAUTH2_CLIENT_EXISTS = new ErrorCode(1_002_020_001, "OAuth2 客户端编号已存在"); ErrorCode OAUTH2_CLIENT_EXISTS = new ErrorCode(1_002_020_001, "OAuth2 客户端编号已存在");

49
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java

@ -7,6 +7,7 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
@ -56,6 +57,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_THIRD_LOGIN_NOT_BIND; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_THIRD_LOGIN_NOT_BIND;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_AUTH_FAILURE;
@Tag(name = "管理后台 - 认证") @Tag(name = "管理后台 - 认证")
@RestController @RestController
@ -102,21 +104,40 @@ public class AuthController {
@PostMapping("/app_login") @PostMapping("/app_login")
@Operation(summary = "社交快捷登录,使用 code 授权码") @Operation(summary = "社交快捷登录,使用 code 授权码")
public CommonResult<AuthLoginRespVO> AppLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) { public CommonResult<AuthLoginRespVO> AppLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) {
final AdminUserDO user = authService.miniAppLogin(reqVO); log.info("[AppLogin][小程序登录开始,code({}) type({}) userType({})]",
reqVO.getCode(), reqVO.getType(), reqVO.getUserType());
if (!user.getIsBand()) {
//添加绑定 try {
SocialUserBindReqDTO userBindReqDTO = new SocialUserBindReqDTO(); final AdminUserDO user = authService.miniAppLogin(reqVO);
userBindReqDTO.setUserId(user.getId());
userBindReqDTO.setUserType(UserTypeEnum.MEMBER.getValue()); if (!user.getIsBand()) {
userBindReqDTO.setCode(reqVO.getCode()); log.info("[AppLogin][新用户绑定社交账号,userId({})]", user.getId());
userBindReqDTO.setSocialType(reqVO.getType()); //添加绑定
userBindReqDTO.setState(reqVO.getState()); SocialUserBindReqDTO userBindReqDTO = new SocialUserBindReqDTO();
socialUserService.bindSocialUser(userBindReqDTO); userBindReqDTO.setUserId(user.getId());
//给用户添加默认角色 可以编辑用户信息, 可以上传图片 userBindReqDTO.setUserType(UserTypeEnum.MEMBER.getValue());
} userBindReqDTO.setCode(reqVO.getCode());
userBindReqDTO.setSocialType(reqVO.getType());
userBindReqDTO.setState(reqVO.getState());
socialUserService.bindSocialUser(userBindReqDTO);
//给用户添加默认角色 可以编辑用户信息, 可以上传图片
}
AuthLoginRespVO respVO = authService.createTokenAfterLoginSuccess2(
user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
return success(authService.createTokenAfterLoginSuccess2(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL)); log.info("[AppLogin][小程序登录成功,userId({}) username({}) token({})]",
user.getId(), user.getUsername(), respVO.getAccessToken());
return success(respVO);
} catch (ServiceException e) {
log.error("[AppLogin][小程序登录失败,code({}) error({})]", reqVO.getCode(), e.getMessage());
return error(e.getCode(), e.getMessage());
} catch (Exception e) {
log.error("[AppLogin][小程序登录异常,code({})]", reqVO.getCode(), e);
return error(SOCIAL_USER_AUTH_FAILURE.getCode(), "登录失败,请重试");
}
} }
@PermitAll @PermitAll

129
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java

@ -6,6 +6,7 @@ import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
@ -317,57 +318,95 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@Override @Override
@Transactional @Transactional
public AdminUserDO miniAppLogin(AuthSocialLoginReqVO reqVO) { public AdminUserDO miniAppLogin(AuthSocialLoginReqVO reqVO) {
log.info("[miniAppLogin][开始小程序登录,code({}) type({}) userType({})]",
reqVO.getCode(), reqVO.getType(), reqVO.getUserType());
try {
AuthUser authUser = socialClientService.getAuthUser(
SocialTypeEnum.WECHAT_MINI_APP.getType(),
UserTypeEnum.ADMIN.getValue(),// 假设用户类型为会员
reqVO.getCode(),
reqVO.getState()
);
log.info("[miniAppLogin][获取到用户信息,openId({}) nickname({})]",
authUser.getUuid(), authUser.getNickname());
final SocialUserDO socialUserDO = socialUserService.selectBySocialTypeAndOpenId(
SocialTypeEnum.WECHAT_MINI_APP.getType(), authUser.getUuid());
AdminUserDO user = null;
if (socialUserDO == null ) {
log.info("[miniAppLogin][新用户注册,openId({})]", authUser.getUuid());
// String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
// "?access_token=" + authUser.getToken() +
// "&openid=" + authUser.getUuid() +
// "&lang=zh_CN";
// String userInfoResponse = HttpUtil.get(userInfoUrl);
// JSONObject userInfoJson = JSONUtil.parseObj(userInfoResponse);
// String nickname = userInfoJson.getStr("nickname");
// 未找到社交用户,插入记录
SocialUserDO socialUser = new SocialUserDO();
socialUser.setType(reqVO.getType());
socialUser.setOpenid(authUser.getUuid());
socialUser.setCode(reqVO.getCode());
socialUser.setAvatar(authUser.getAvatar());
socialUser.setRawTokenInfo(authUser.getToken().getRefreshToken() != null? authUser.getToken().getRefreshToken(): "default" );
socialUser.setNickname(authUser.getNickname());
socialUser.setState(reqVO.getState());
socialUser.setRawUserInfo(authUser.getRawUserInfo() != null? authUser.getRawUserInfo().toString(): "default");
final int insert = socialUserMapper.insert(socialUser);
if (insert < 0) {
log.error("[miniAppLogin][插入社交用户失败,openId({})]", authUser.getUuid());
throw exception(INSERT_ERROR);
}
user = userService.autoRegisterUser(authUser, reqVO.getUserType());
//给用户付一个普通用户角色可以上传图片
UserRoleDO userRoleDO = new UserRoleDO();
userRoleDO.setUserId(user.getId());
userRoleDO.setRoleId(2l);
userRoleMapper.insert(userRoleDO);
user.setIsBand(false);
log.info("[miniAppLogin][新用户注册成功,userId({}) username({})]", user.getId(), user.getUsername());
} else {
log.info("[miniAppLogin][已有用户登录,socialUserId({})]", socialUserDO.getId());
SocialUserBindDO bind = socialUserBindMapper.selectByUserTypeAndSocialUserId(
UserTypeEnum.MEMBER.getValue(), socialUserDO.getId());
if (bind == null) {
log.error("[miniAppLogin][未找到用户绑定信息,socialUserId({})]", socialUserDO.getId());
throw exception(SOCIAL_USER_NOT_FOUND);
}
AuthUser authUser = socialClientService.getAuthUser( // // 获得用户
SocialTypeEnum.WECHAT_MINI_APP.getType(), user = userService.getUser(bind.getUserId());
UserTypeEnum.ADMIN.getValue(),// 假设用户类型为会员
reqVO.getCode(),
reqVO.getState()
);
final SocialUserDO socialUserDO = socialUserService.selectBySocialTypeAndOpenId(SocialTypeEnum.WECHAT_MINI_APP.getType(), authUser.getUuid());
AdminUserDO user = null;
if (socialUserDO == null ) {
// 未找到社交用户,插入记录
SocialUserDO socialUser = new SocialUserDO();
socialUser.setType(reqVO.getType());
socialUser.setOpenid(authUser.getUuid());
socialUser.setCode(reqVO.getCode());
socialUser.setAvatar(authUser.getAvatar());
socialUser.setRawTokenInfo(authUser.getToken().getRefreshToken() != null? authUser.getToken().getRefreshToken(): "default" );
socialUser.setNickname(authUser.getNickname());
socialUser.setState(reqVO.getState());
socialUser.setRawUserInfo(authUser.getRawUserInfo() != null? authUser.getRawUserInfo().toString(): "default");
final int insert = socialUserMapper.insert(socialUser);
if (insert < 0) {
throw exception(INSERT_ERROR);
}
user = userService.autoRegisterUser(authUser, reqVO.getUserType());
//给用户付一个普通用户角色可以上传图片
UserRoleDO userRoleDO = new UserRoleDO();
userRoleDO.setUserId(user.getId());
userRoleDO.setRoleId(2l);
userRoleMapper.insert(userRoleDO);
user.setIsBand(false); if (user == null) {
log.error("[miniAppLogin][用户不存在,userId({})]", bind.getUserId());
throw exception(USER_NOT_EXISTS);
}
} else { user.setIsBand(true);
log.info("[miniAppLogin][用户登录成功,userId({}) username({})]", user.getId(), user.getUsername());
}
SocialUserBindDO bind = socialUserBindMapper.selectByUserTypeAndSocialUserId(UserTypeEnum.MEMBER.getValue(), socialUserDO.getId()); return user;
// // 获得用户
user = userService.getUser(bind.getUserId());
if (user == null) { } catch (ServiceException e) {
throw exception(USER_NOT_EXISTS); log.error("[miniAppLogin][小程序登录失败,code({}) error({})]", reqVO.getCode(), e.getMessage());
} throw e;
user.setIsBand(true); } catch (Exception e) {
log.error("[miniAppLogin][小程序登录异常,code({})]", reqVO.getCode(), e);
throw exception(SOCIAL_USER_AUTH_FAILURE, e.getMessage());
} }
return user;
} }

42
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java

@ -14,6 +14,7 @@ import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.cache.CacheUtils; import cn.iocoder.yudao.framework.common.util.cache.CacheUtils;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
@ -158,14 +159,43 @@ public class SocialClientServiceImpl implements SocialClientService {
// 构建请求 // 构建请求
AuthRequest authRequest = buildAuthRequest(socialType, userType); AuthRequest authRequest = buildAuthRequest(socialType, userType);
AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build(); AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build();
// 执行请求
AuthResponse<?> authResponse = authRequest.login(authCallback); try {
log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", socialType, // 执行请求
log.info("[getAuthUser][开始请求社交平台,type({}) userType({}) code({})]", socialType, userType, code);
AuthResponse<?> authResponse = authRequest.login(authCallback);
log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", socialType,
toJsonString(authCallback), toJsonString(authResponse)); toJsonString(authCallback), toJsonString(authResponse));
if (!authResponse.ok()) {
throw exception(SOCIAL_USER_AUTH_FAILURE, authResponse.getMsg()); if (!authResponse.ok()) {
// 分析错误原因
String errorMsg = authResponse.getMsg();
log.error("[getAuthUser][社交授权失败,type({}) code({}) errorMsg({})]", socialType, code, errorMsg);
// 根据错误信息判断具体错误类型
if (errorMsg != null) {
if (errorMsg.contains("invalid code") || errorMsg.contains("40163") || errorMsg.contains("code been used")) {
throw exception(SOCIAL_USER_CODE_INVALID);
} else if (errorMsg.contains("code expired") || errorMsg.contains("40029")) {
throw exception(SOCIAL_USER_CODE_EXPIRED);
} else if (errorMsg.contains("network") || errorMsg.contains("timeout")) {
throw exception(SOCIAL_USER_NETWORK_ERROR);
}
}
// 默认错误
throw exception(SOCIAL_USER_AUTH_FAILURE, authResponse.getMsg());
}
return (AuthUser) authResponse.getData();
} catch (Exception e) {
// 捕获其他异常
if (e instanceof ServiceException) {
throw e; // 如果是我们的业务异常,直接抛出
}
log.error("[getAuthUser][请求社交平台异常,type({}) code({}) error({})]", socialType, code, e.getMessage(), e);
throw exception(SOCIAL_USER_NETWORK_ERROR);
} }
return (AuthUser) authResponse.getData();
} }
/** /**

Loading…
Cancel
Save