From 9be00d6035d5ba76b1a6ee96590446e7d9a57aa3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 2 Oct 2021 23:55:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=95=B4=E5=AE=8C=E6=88=90=E9=92=89?= =?UTF-8?q?=E9=92=89=E7=9A=84=E4=B8=89=E6=96=B9=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/auth/SysAuthController.java | 46 +++--- .../vo/auth/SysAuthSocialLogin2ReqVO.java | 48 ++++++ ...eqVO.java => SysAuthSocialLoginReqVO.java} | 8 +- .../system/convert/auth/SysAuthConvert.java | 10 +- ...UserSocialDO.java => SysSocialUserDO.java} | 23 +-- .../mysql/social/SysSysUserSocialMapper.java | 4 +- .../dal/mysql/social/SysUserSocialMapper.java | 4 +- .../dal/mysql/user/SysSocialUserMapper.java | 18 ++ .../dal/redis/SysRedisKeyConstants.java | 7 + .../redis/auth/SysAuthSocialUserRedisDAO.java | 38 +++++ .../dal/redis/auth/SysLoginUserRedisDAO.java | 2 +- .../system/enums/SysErrorCodeConstants.java | 3 + .../enums/logger/SysLoginLogTypeEnum.java | 1 + .../enums/user/SysUserSocialTypeEnum.java | 5 +- .../system/service/auth/SysAuthService.java | 17 +- .../service/auth/impl/SysAuthServiceImpl.java | 154 +++++++++++++++--- .../service/user/SysUserServiceImpl.java | 4 +- yudao-admin-ui/src/api/login.js | 27 ++- yudao-admin-ui/src/permission.js | 2 +- yudao-admin-ui/src/router/index.js | 4 +- yudao-admin-ui/src/store/modules/user.js | 38 ++++- yudao-admin-ui/src/views/login.vue | 8 +- .../views/{thirdLogin.vue => socialLogin.vue} | 24 ++- 23 files changed, 401 insertions(+), 94 deletions(-) create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialLogin2ReqVO.java rename yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/{SysAuthThirdLoginReqVO.java => SysAuthSocialLoginReqVO.java} (83%) rename yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/user/{SysUserSocialDO.java => SysSocialUserDO.java} (75%) create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysSocialUserMapper.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/auth/SysAuthSocialUserRedisDAO.java rename yudao-admin-ui/src/views/{thirdLogin.vue => socialLogin.vue} (86%) diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/SysAuthController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/SysAuthController.java index b6ee6b27f..b4e57c867 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/SysAuthController.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/SysAuthController.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.adminserver.modules.system.controller.auth; -import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.*; import cn.iocoder.yudao.adminserver.modules.system.convert.auth.SysAuthConvert; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO; @@ -23,9 +22,6 @@ import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; -import me.zhyd.oauth.model.AuthCallback; -import me.zhyd.oauth.model.AuthResponse; -import me.zhyd.oauth.model.AuthUser; import me.zhyd.oauth.request.AuthRequest; import me.zhyd.oauth.utils.AuthStateUtils; import org.springframework.validation.annotation.Validated; @@ -100,16 +96,16 @@ public class SysAuthController { return success(SysAuthConvert.INSTANCE.buildMenuTree(menuList)); } - // ========== 三方登陆相关 ========== + // ========== 社交登陆相关 ========== - @GetMapping("/third-login-redirect") - @ApiOperation("三方登陆的跳转") + @GetMapping("/social-login-redirect") + @ApiOperation("社交登陆的跳转") @ApiImplicitParams({ @ApiImplicitParam(name = "type", value = "三方类型", required = true, dataTypeClass = Integer.class), @ApiImplicitParam(name = "redirectUri", value = "回调路径", dataTypeClass = String.class) }) - public CommonResult thirdLoginRedirect(@RequestParam("type") Integer type, - @RequestParam("redirectUri") String redirectUri) { + public CommonResult socialLoginRedirect(@RequestParam("type") Integer type, + @RequestParam("redirectUri") String redirectUri) { // 获得对应的 AuthRequest 实现 AuthRequest authRequest = authRequestFactory.get(SysUserSocialTypeEnum.valueOfType(type).getSource()); // 生成跳转地址 @@ -118,20 +114,30 @@ public class SysAuthController { return CommonResult.success(authorizeUri); } - @PostMapping("/third-login") - @ApiOperation("三方登陆,使用 code 授权码") + @PostMapping("/social-login") + @ApiOperation("社交登陆,使用 code 授权码") @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 - public CommonResult thirdLogin(@RequestBody @Valid SysAuthThirdLoginReqVO reqVO) { - String token = authService.thirdLogin(reqVO, getClientIP(), getUserAgent()); - return null; + public CommonResult socialLogin(@RequestBody @Valid SysAuthSocialLoginReqVO reqVO) { + String token = authService.socialLogin(reqVO, getClientIP(), getUserAgent()); + // 返回结果 + return success(SysAuthLoginRespVO.builder().token(token).build()); } - @RequestMapping("/{type}/callback") - public AuthResponse login(@PathVariable String type, AuthCallback callback) { - AuthRequest authRequest = authRequestFactory.get(type); - AuthResponse response = authRequest.login(callback); - log.info("【response】= {}", JSONUtil.toJsonStr(response)); - return response; + @PostMapping("/social-login2") + @ApiOperation("社交登陆,使用 code 授权码 + 账号密码") + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 + public CommonResult socialLogin2(@RequestBody @Valid SysAuthSocialLogin2ReqVO reqVO) { + String token = authService.socialLogin2(reqVO, getClientIP(), getUserAgent()); + // 返回结果 + return success(SysAuthLoginRespVO.builder().token(token).build()); } +// @RequestMapping("/{type}/callback") +// public AuthResponse login(@PathVariable String type, AuthCallback callback) { +// AuthRequest authRequest = authRequestFactory.get(type); +// AuthResponse response = authRequest.login(callback); +// log.info("【response】= {}", JSONUtil.toJsonStr(response)); +// return response; +// } + } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialLogin2ReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialLogin2ReqVO.java new file mode 100644 index 000000000..6b7e892f5 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialLogin2ReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth; + +import cn.iocoder.yudao.adminserver.modules.system.enums.user.SysUserSocialTypeEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +@ApiModel("社交登陆 Request VO,使用 code 授权码 + 账号密码") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SysAuthSocialLogin2ReqVO { + + @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值") + @InEnum(SysUserSocialTypeEnum.class) + @NotNull(message = "社交平台的类型不能为空") + private Integer type; + + @ApiModelProperty(value = "授权码", required = true, example = "1024") + @NotEmpty(message = "授权码不能为空") + private String code; + + @ApiModelProperty(value = "state", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") + @NotEmpty(message = "state 不能为空") + private String state; + + @ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma") + @NotEmpty(message = "登陆账号不能为空") + @Length(min = 4, max = 16, message = "账号长度为 4-16 位") + @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") + private String username; + + @ApiModelProperty(value = "密码", required = true, example = "buzhidao") + @NotEmpty(message = "密码不能为空") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthThirdLoginReqVO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialLoginReqVO.java similarity index 83% rename from yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthThirdLoginReqVO.java rename to yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialLoginReqVO.java index c1e08a0e2..6aa03eade 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthThirdLoginReqVO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialLoginReqVO.java @@ -14,16 +14,16 @@ import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; -@ApiModel("三方登陆 Request VO,使用 code 授权码") +@ApiModel("社交登陆 Request VO,使用 code 授权码") @Data @NoArgsConstructor @AllArgsConstructor @Builder -public class SysAuthThirdLoginReqVO { +public class SysAuthSocialLoginReqVO { - @ApiModelProperty(value = "三方平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值") + @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值") @InEnum(SysUserSocialTypeEnum.class) - @NotNull(message = "三方平台的类型不能为空") + @NotNull(message = "社交平台的类型不能为空") private Integer type; @ApiModelProperty(value = "授权码", required = true, example = "1024") diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/auth/SysAuthConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/auth/SysAuthConvert.java index 779c43658..225f21b9a 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/auth/SysAuthConvert.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/auth/SysAuthConvert.java @@ -2,10 +2,10 @@ package cn.iocoder.yudao.adminserver.modules.system.convert.auth; import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthMenuRespVO; import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthPermissionInfoRespVO; -import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthThirdLoginReqVO; +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLogin2ReqVO; +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLoginReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdatePasswordReqVO; import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdateReqVO; -import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.SysUserCreateReqVO; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO; @@ -13,10 +13,8 @@ import cn.iocoder.yudao.adminserver.modules.system.enums.permission.MenuIdEnum; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.security.core.LoginUser; import me.zhyd.oauth.model.AuthCallback; -import me.zhyd.oauth.model.AuthUser; import org.mapstruct.Mapper; import org.mapstruct.Mapping; -import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; import org.slf4j.LoggerFactory; @@ -45,7 +43,9 @@ public interface SysAuthConvert { LoginUser convert(SysUserProfileUpdatePasswordReqVO reqVO); - AuthCallback convert(SysAuthThirdLoginReqVO bean); + AuthCallback convert(SysAuthSocialLoginReqVO bean); + + AuthCallback convert(SysAuthSocialLogin2ReqVO bean); /** * 将菜单列表,构建成菜单树 diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/user/SysUserSocialDO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/user/SysSocialUserDO.java similarity index 75% rename from yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/user/SysUserSocialDO.java rename to yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/user/SysSocialUserDO.java index e201262d1..66c3043a9 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/user/SysUserSocialDO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/user/SysSocialUserDO.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user; -import cn.iocoder.yudao.adminserver.modules.system.enums.user.SysUserSocialTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.TableId; @@ -8,18 +7,18 @@ import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; /** - * 三方登陆信息 - * 通过 {@link SysUserSocialDO#getUserId()} 关联到对应的 {@link SysUserDO} + * 社交用户 + * 通过 {@link SysSocialUserDO#getUserId()} 关联到对应的 {@link SysUserDO} * * @author weir */ -@TableName(value = "sys_user_social", autoResultMap = true) +@TableName(value = "sys_social_user", autoResultMap = true) @Data @EqualsAndHashCode(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor -public class SysUserSocialDO extends BaseDO { +public class SysSocialUserDO extends BaseDO { /** * 自增主键 @@ -27,7 +26,7 @@ public class SysUserSocialDO extends BaseDO { @TableId private Long id; /** - * 用户编号 + * 关联的用户编号 */ private Long userId; /** @@ -38,20 +37,22 @@ public class SysUserSocialDO extends BaseDO { private Integer userType; /** - * 三方平台的类型 + * 社交平台的类型 + * + * 枚举 {@link UserTypeEnum} */ - private SysUserSocialTypeEnum type; + private Integer type; /** - * 三方 openid + * 社交 openid */ private String openid; /** - * 三方 token + * 社交 token */ private String token; /** - * 三方的全局编号 + * 社交的全局编号 * * 例如说,微信平台的 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html * 如果没有 unionId 的平台,直接使用 openid 作为该字段的值 diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/social/SysSysUserSocialMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/social/SysSysUserSocialMapper.java index 6d010ccc3..f06d408f3 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/social/SysSysUserSocialMapper.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/social/SysSysUserSocialMapper.java @@ -1,11 +1,11 @@ package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social; -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserSocialDO; +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysSocialUserDO; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import org.apache.ibatis.annotations.Mapper; @Mapper -public interface SysSysUserSocialMapper extends BaseMapperX { +public interface SysSysUserSocialMapper extends BaseMapperX { } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/social/SysUserSocialMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/social/SysUserSocialMapper.java index fc3f7d96b..85bed3e36 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/social/SysUserSocialMapper.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/social/SysUserSocialMapper.java @@ -1,11 +1,11 @@ package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social; -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserSocialDO; +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysSocialUserDO; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import org.apache.ibatis.annotations.Mapper; @Mapper -public interface SysUserSocialMapper extends BaseMapperX { +public interface SysUserSocialMapper extends BaseMapperX { } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysSocialUserMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysSocialUserMapper.java new file mode 100644 index 000000000..55e9b723f --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysSocialUserMapper.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.user; + +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysSocialUserDO; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface SysSocialUserMapper extends BaseMapperX { + + default List selectListByTypeAndUnionId(Integer userType, Integer type, String unionId) { + return selectList(new QueryWrapper().eq("user_type", userType) + .eq("type", type).eq("union_id", unionId)); + } + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/SysRedisKeyConstants.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/SysRedisKeyConstants.java index 525b084bd..b128fa966 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/SysRedisKeyConstants.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/SysRedisKeyConstants.java @@ -2,6 +2,9 @@ package cn.iocoder.yudao.adminserver.modules.system.dal.redis; import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine; import cn.iocoder.yudao.framework.security.core.LoginUser; +import me.zhyd.oauth.model.AuthUser; + +import java.time.Duration; import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING; @@ -20,4 +23,8 @@ public interface SysRedisKeyConstants { "captcha_code:%s", // 参数为 uuid STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); + RedisKeyDefine AUTH_SOCIAL_USER = new RedisKeyDefine("认证的三方用户", + "auth_social_user:%d:%s", // 参数为 type,code + STRING, AuthUser.class, Duration.ofDays(1)); + } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/auth/SysAuthSocialUserRedisDAO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/auth/SysAuthSocialUserRedisDAO.java new file mode 100644 index 000000000..945bc65fc --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/auth/SysAuthSocialUserRedisDAO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.adminserver.modules.system.dal.redis.auth; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthUser; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.adminserver.modules.system.dal.redis.SysRedisKeyConstants.AUTH_SOCIAL_USER; + +/** + * 社交 {@link me.zhyd.oauth.model.AuthUser} 的 RedisDAO + * + * @author 芋道源码 + */ +@Repository +public class SysAuthSocialUserRedisDAO { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + public AuthUser get(Integer type, AuthCallback authCallback) { + String redisKey = formatKey(type, authCallback.getCode()); + return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), AuthUser.class); + } + + public void set(Integer type, AuthCallback authCallback, AuthUser authUser) { + String redisKey = formatKey(type, authCallback.getCode()); + stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(authUser), AUTH_SOCIAL_USER.getTimeout()); + } + + private static String formatKey(Integer type, String code) { + return String.format(AUTH_SOCIAL_USER.getKeyTemplate(), type, code); + } + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/auth/SysLoginUserRedisDAO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/auth/SysLoginUserRedisDAO.java index d62bbb059..6ca358a4a 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/auth/SysLoginUserRedisDAO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/auth/SysLoginUserRedisDAO.java @@ -22,7 +22,7 @@ public class SysLoginUserRedisDAO { @Resource private StringRedisTemplate stringRedisTemplate; @Resource - private SysUserSessionService sysUserSessionService; + private SysUserSessionService sysUserSessionService; // TODO 芋艿:得看看怎么拿出去 public LoginUser get(String sessionId) { String redisKey = formatKey(sessionId); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java index 378cc55bc..069d2b4ab 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.adminserver.modules.system.enums; +import cn.iocoder.yudao.adminserver.modules.tool.framework.errorcode.config.ErrorCodeConfiguration; import cn.iocoder.yudao.framework.common.exception.ErrorCode; /** @@ -15,6 +16,8 @@ public interface SysErrorCodeConstants { ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1002000002, "登录失败"); // 登陆失败的兜底,位置原因 ErrorCode AUTH_LOGIN_CAPTCHA_NOT_FOUND = new ErrorCode(1002000003, "验证码不存在"); ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1002000004, "验证码不正确"); + ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1002000005, "未绑定账号,需要进行绑定"); + ErrorCode AUTH_THIRD_OAUTH_FAILURE = new ErrorCode(1002000006, "三方授权失败,原因是:{}"); // ========== TOKEN 模块 1002001000 ========== ErrorCode TOKEN_EXPIRED = new ErrorCode(1002001000, "Token 已经过期"); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/logger/SysLoginLogTypeEnum.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/logger/SysLoginLogTypeEnum.java index d9aa2eb26..bfded0503 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/logger/SysLoginLogTypeEnum.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/logger/SysLoginLogTypeEnum.java @@ -11,6 +11,7 @@ import lombok.Getter; public enum SysLoginLogTypeEnum { LOGIN_USERNAME(100), // 使用账号登录 + LOGIN_SOCIAL(101), // 使用社交登陆 LOGOUT_SELF(200), // 自己主动登出 LOGOUT_TIMEOUT(201), // 超时登出 diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/user/SysUserSocialTypeEnum.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/user/SysUserSocialTypeEnum.java index 3320d3a9c..96ae75770 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/user/SysUserSocialTypeEnum.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/user/SysUserSocialTypeEnum.java @@ -1,17 +1,14 @@ package cn.iocoder.yudao.adminserver.modules.system.enums.user; import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.yudao.adminserver.modules.system.enums.errorcode.SysErrorCodeTypeEnum; import cn.iocoder.yudao.framework.common.core.IntArrayValuable; -import com.fasterxml.jackson.annotation.JsonCreator; -import jodd.util.ArraysUtil; import lombok.AllArgsConstructor; import lombok.Getter; import java.util.Arrays; /** - * 用户的三方平台的类型枚举 + * 用户的社交平台的类型枚举 * * @author 芋道源码 */ diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthService.java index 90e41deb7..406179aa1 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthService.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.adminserver.modules.system.service.auth; -import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthThirdLoginReqVO; +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLogin2ReqVO; +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLoginReqVO; import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthLoginReqVO; @@ -24,13 +25,23 @@ public interface SysAuthService extends SecurityAuthFrameworkService { String login(SysAuthLoginReqVO reqVO, String userIp, String userAgent); /** - * 三方登陆用户,使用 code 授权码 + * 社交登陆用户,使用 code 授权码 * * @param reqVO 登陆信息 * @param userIp 用户 IP * @param userAgent 用户 UA * @return 身份令牌,使用 JWT 方式 */ - String thirdLogin(SysAuthThirdLoginReqVO reqVO, String userIp, String userAgent); + String socialLogin(SysAuthSocialLoginReqVO reqVO, String userIp, String userAgent); + + /** + * 社交登陆用户,使用 code 授权码 + 账号密码 + * + * @param reqVO 登陆信息 + * @param userIp 用户 IP + * @param userAgent 用户 UA + * @return 身份令牌,使用 JWT 方式 + */ + String socialLogin2(SysAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent); } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java index 404719780..0677c2e11 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java @@ -1,9 +1,15 @@ package cn.iocoder.yudao.adminserver.modules.system.service.auth.impl; -import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthThirdLoginReqVO; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLogin2ReqVO; +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLoginReqVO; +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysSocialUserDO; +import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.user.SysSocialUserMapper; +import cn.iocoder.yudao.adminserver.modules.system.dal.redis.auth.SysAuthSocialUserRedisDAO; import cn.iocoder.yudao.adminserver.modules.system.enums.user.SysUserSocialTypeEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.security.core.LoginUser; @@ -40,6 +46,8 @@ import org.springframework.stereotype.Service; import org.springframework.util.Assert; import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -58,6 +66,7 @@ public class SysAuthServiceImpl implements SysAuthService { @Resource @Lazy // 延迟加载,因为存在相互依赖的问题 private AuthenticationManager authenticationManager; + @Resource private SysUserService userService; @Resource @@ -69,6 +78,11 @@ public class SysAuthServiceImpl implements SysAuthService { @Resource private SysUserSessionService userSessionService; + @Resource + private SysAuthSocialUserRedisDAO authSocialUserRedisDAO; + @Resource + private SysSocialUserMapper socialUserMapper; + @Resource private AuthRequestFactory authRequestFactory; @@ -109,24 +123,6 @@ public class SysAuthServiceImpl implements SysAuthService { return userSessionService.createUserSession(loginUser, userIp, userAgent); } - @Override - public String thirdLogin(SysAuthThirdLoginReqVO reqVO, String userIp, String userAgent) { - // 使用 code 授权码,进行登陆 - AuthRequest authRequest = authRequestFactory.get(SysUserSocialTypeEnum.valueOfType(reqVO.getType()).getSource()); - AuthCallback authCallback = SysAuthConvert.INSTANCE.convert(reqVO); - AuthResponse authResponse = authRequest.login(authCallback); - log.info("[thirdLogin][请求三方平台 type({}) request({}) response({})]", reqVO.getType(), JsonUtils.toJsonString(authCallback), - JsonUtils.toJsonString(authResponse)); - if (!authResponse.ok()) { - throw new RuntimeException(""); // TODO 芋艿:补全 - } - AuthUser authUser = (AuthUser) authResponse.getData(); - - // 查找到对应的 - - return null; - } - private void verifyCaptcha(String username, String captchaUUID, String captchaCode) { String code = captchaService.getCaptchaCode(captchaUUID); // 验证码不存在 @@ -190,6 +186,124 @@ public class SysAuthServiceImpl implements SysAuthService { return permissionService.getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus())); } + @Override + public String socialLogin(SysAuthSocialLoginReqVO reqVO, String userIp, String userAgent) { + // 使用 code 授权码,进行登陆 + AuthCallback authCallback = SysAuthConvert.INSTANCE.convert(reqVO); + AuthUser authUser = this.obtainAuthUserFromCache(reqVO.getType(), authCallback); + + // 如果未绑定 SysSocialUserDO 用户,则无法自动登陆,进行报错 + String unionId = getAuthUserUnionId(authUser); + List socialUsers = socialUserMapper.selectListByTypeAndUnionId(UserTypeEnum.ADMIN.getValue(), + reqVO.getType(), unionId); + if (CollUtil.isEmpty(socialUsers)) { + throw exception(AUTH_THIRD_LOGIN_NOT_BIND); + } + + // 使用账号密码,进行登陆。 + SysUserDO user = userService.getUser(socialUsers.get(0).getUserId()); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); + // TODO 芋艿:需要改造下,增加各种登陆方式 + loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表 + + // 保存社交用户 + this.saveSocialUser(reqVO.getType(), socialUsers, loginUser.getId(), authUser); + + // 缓存登陆用户到 Redis 中,返回 sessionId 编号 + return userSessionService.createUserSession(loginUser, userIp, userAgent); + } + + @Override + public String socialLogin2(SysAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent) { + // 使用 code 授权码,进行登陆 + AuthCallback authCallback = SysAuthConvert.INSTANCE.convert(reqVO); + AuthUser authUser = this.obtainAuthUserFromCache(reqVO.getType(), authCallback); + + // 查询社交对应的 SysSocialUserDO 用户 + String unionId = getAuthUserUnionId(authUser); + List socialUsers = socialUserMapper.selectListByTypeAndUnionId(UserTypeEnum.ADMIN.getValue(), + reqVO.getType(), unionId); + + // 使用账号密码,进行登陆。 + LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword()); // TODO 芋艿:需要改造下,增加各种登陆方式 + loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表 + + // 保存社交用户 + this.saveSocialUser(reqVO.getType(), socialUsers, loginUser.getId(), authUser); + + // 缓存登陆用户到 Redis 中,返回 sessionId 编号 + return userSessionService.createUserSession(loginUser, userIp, userAgent); + } + + private static String getAuthUserUnionId(AuthUser authUser) { + return StrUtil.blankToDefault(authUser.getToken().getUnionId(), authUser.getUuid()); + } + + private AuthUser obtainAuthUserFromCache(Integer type, AuthCallback authCallback) { + // 从缓存中获取 + AuthUser authUser = authSocialUserRedisDAO.get(type, authCallback); + if (authUser != null) { + return authUser; + } + + // 请求获取 + authUser = this.obtainAuthUser(type, authCallback); + authSocialUserRedisDAO.set(type, authCallback, authUser); + return authUser; + } + + private AuthUser obtainAuthUser(Integer type, AuthCallback authCallback) { + AuthRequest authRequest = authRequestFactory.get(SysUserSocialTypeEnum.valueOfType(type).getSource()); + AuthResponse authResponse = authRequest.login(authCallback); + log.info("[obtainAuthUser][请求三方平台 type({}) request({}) response({})]", type, JsonUtils.toJsonString(authCallback), + JsonUtils.toJsonString(authResponse)); + if (!authResponse.ok()) { + throw exception(AUTH_THIRD_OAUTH_FAILURE, authResponse.getMsg()); + } + return (AuthUser) authResponse.getData(); + } + + /** + * 保存社交用户 + * + * @param socialUsers 已存在的社交用户列表 + * @param userId 绑定的用户编号 + * @param authUser 需要保存的社交用户信息 + */ + private void saveSocialUser(Integer type, List socialUsers, Long userId, AuthUser authUser) { + // 逻辑一:如果 socialUsers 指定的 userId 改变,需要进行更新 + // 例如说,一个微信 unionId 对应了多个社交账号,结果其中有个关联了新的 userId,则其它也要跟着修改 + // 考虑到 socialUsers 一般比较少,直接 for 循环更新即可 + socialUsers.forEach(socialUser -> { + if (Objects.equals(socialUser.getUserId(), userId)) { + return; + } + socialUserMapper.updateById(new SysSocialUserDO().setUserId(socialUser.getUserId()).setUserId(userId)); + }); + + // 逻辑二:如果 authUser 不存在于 socialUsers 中,则进行新增;否则,进行更新 + SysSocialUserDO saveSocialUser = CollUtil.findOneByField(socialUsers, "openid", authUser.getUuid()); + if (saveSocialUser == null) { + saveSocialUser = new SysSocialUserDO(); + saveSocialUser.setUserId(userId).setUserType(UserTypeEnum.ADMIN.getValue()); + saveSocialUser.setType(type).setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()) + .setUnionId(getAuthUserUnionId(authUser)).setRawTokenInfo(JsonUtils.toJsonString(authUser.getToken())); + saveSocialUser.setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()) + .setRawUserInfo(JsonUtils.toJsonString(authUser.getRawUserInfo())); + socialUserMapper.insert(saveSocialUser); + } else { + saveSocialUser = new SysSocialUserDO().setId(saveSocialUser.getId()); + saveSocialUser.setToken(authUser.getToken().getAccessToken()).setUnionId(getAuthUserUnionId(authUser)) + .setRawTokenInfo(JsonUtils.toJsonString(authUser.getToken())); + saveSocialUser.setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()) + .setRawUserInfo(JsonUtils.toJsonString(authUser.getRawUserInfo())); + socialUserMapper.updateById(saveSocialUser); + } + } + @Override public void logout(String token) { // 查询用户信息 diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImpl.java index fc4801b62..ec585dbc8 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImpl.java @@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserSocialDO; +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysSocialUserDO; import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social.SysUserSocialMapper; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.exception.ServiceException; @@ -80,7 +80,7 @@ public class SysUserServiceImpl implements SysUserService { @Override public Long bindSocialUSer(Long sysUserId, String socialUSerId) { - SysUserSocialDO userSocialDO = new SysUserSocialDO(); + SysSocialUserDO userSocialDO = new SysSocialUserDO(); userSocialDO.setUserId(sysUserId); // userSocialDO.setSocialUserId(socialUSerId); userSocialMapper.insert(userSocialDO); diff --git a/yudao-admin-ui/src/api/login.js b/yudao-admin-ui/src/api/login.js index 7f02e4ac4..4517ee42d 100644 --- a/yudao-admin-ui/src/api/login.js +++ b/yudao-admin-ui/src/api/login.js @@ -39,18 +39,18 @@ export function getCodeImg() { }) } -// 三方登陆的跳转 -export function thirdLoginRedirect(type, redirectUri) { +// 社交登陆的跳转 +export function socialLoginRedirect(type, redirectUri) { return request({ - url: '/third-login-redirect?type=' + type + '&redirectUri=' + redirectUri, + url: '/social-login-redirect?type=' + type + '&redirectUri=' + redirectUri, method: 'get' }) } -// 三方登陆,使用 code 授权码 -export function thirdLogin(type, code, state) { +// 社交登陆,使用 code 授权码 +export function socialLogin(type, code, state) { return request({ - url: '/third-login', + url: '/social-login', method: 'post', data: { type, @@ -59,3 +59,18 @@ export function thirdLogin(type, code, state) { } }) } + +// 社交登陆,使用 code 授权码 + + 账号密码 +export function socialLogin2(type, code, state, username, password) { + return request({ + url: '/social-login2', + method: 'post', + data: { + type, + code, + state, + username, + password + } + }) +} diff --git a/yudao-admin-ui/src/permission.js b/yudao-admin-ui/src/permission.js index a9eb37128..6b8e5f586 100644 --- a/yudao-admin-ui/src/permission.js +++ b/yudao-admin-ui/src/permission.js @@ -7,7 +7,7 @@ import { getToken } from '@/utils/auth' NProgress.configure({ showSpinner: false }) -const whiteList = ['/login', '/third-login', '/auth-redirect', '/bind', '/register', '/oauthLogin/gitee'] +const whiteList = ['/login', '/social-login', '/auth-redirect', '/bind', '/register', '/oauthLogin/gitee'] router.beforeEach((to, from, next) => { NProgress.start() diff --git a/yudao-admin-ui/src/router/index.js b/yudao-admin-ui/src/router/index.js index c9de88a5a..63f44544b 100644 --- a/yudao-admin-ui/src/router/index.js +++ b/yudao-admin-ui/src/router/index.js @@ -44,8 +44,8 @@ export const constantRoutes = [ hidden: true }, { - path: '/third-login', - component: (resolve) => require(['@/views/thirdLogin'], resolve), + path: '/social-login', + component: (resolve) => require(['@/views/socialLogin'], resolve), hidden: true }, { diff --git a/yudao-admin-ui/src/store/modules/user.js b/yudao-admin-ui/src/store/modules/user.js index eb8669d3a..42560ae29 100644 --- a/yudao-admin-ui/src/store/modules/user.js +++ b/yudao-admin-ui/src/store/modules/user.js @@ -1,4 +1,4 @@ -import { login, logout, getInfo } from '@/api/login' +import {login, logout, getInfo, socialLogin, socialLogin2} from '@/api/login' import { getToken, setToken, removeToken } from '@/utils/auth' const user = { @@ -47,6 +47,42 @@ const user = { }) }, + // 社交登陆 + SocialLogin({ commit }, userInfo) { + const code = userInfo.code + const state = userInfo.state + const type = userInfo.type + return new Promise((resolve, reject) => { + socialLogin(type, code, state).then(res => { + res = res.data; + setToken(res.token) + commit('SET_TOKEN', res.token) + resolve() + }).catch(error => { + reject(error) + }) + }) + }, + + // 社交登陆 + SocialLogin2({ commit }, userInfo) { + const code = userInfo.code + const state = userInfo.state + const type = userInfo.type + const username = userInfo.username.trim() + const password = userInfo.password + return new Promise((resolve, reject) => { + socialLogin2(type, code, state, username, password).then(res => { + res = res.data; + setToken(res.token) + commit('SET_TOKEN', res.token) + resolve() + }).catch(error => { + reject(error) + }) + }) + }, + // 获取用户信息 GetInfo({ commit, state }) { return new Promise((resolve, reject) => { diff --git a/yudao-admin-ui/src/views/login.vue b/yudao-admin-ui/src/views/login.vue index d3a41f2f6..bdff701f0 100644 --- a/yudao-admin-ui/src/views/login.vue +++ b/yudao-admin-ui/src/views/login.vue @@ -45,7 +45,7 @@