Commit 9be00d6035d5ba76b1a6ee96590446e7d9a57aa3
1 parent
e05d9059
完整完成钉钉的三方接入
Showing
23 changed files
with
401 additions
and
94 deletions
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/SysAuthController.java
| 1 | package cn.iocoder.yudao.adminserver.modules.system.controller.auth; | 1 | package cn.iocoder.yudao.adminserver.modules.system.controller.auth; |
| 2 | 2 | ||
| 3 | -import cn.hutool.json.JSONUtil; | ||
| 4 | import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.*; | 3 | import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.*; |
| 5 | import cn.iocoder.yudao.adminserver.modules.system.convert.auth.SysAuthConvert; | 4 | import cn.iocoder.yudao.adminserver.modules.system.convert.auth.SysAuthConvert; |
| 6 | import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO; | 5 | import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO; |
| @@ -23,9 +22,6 @@ import io.swagger.annotations.ApiImplicitParam; | @@ -23,9 +22,6 @@ import io.swagger.annotations.ApiImplicitParam; | ||
| 23 | import io.swagger.annotations.ApiImplicitParams; | 22 | import io.swagger.annotations.ApiImplicitParams; |
| 24 | import io.swagger.annotations.ApiOperation; | 23 | import io.swagger.annotations.ApiOperation; |
| 25 | import lombok.extern.slf4j.Slf4j; | 24 | import lombok.extern.slf4j.Slf4j; |
| 26 | -import me.zhyd.oauth.model.AuthCallback; | ||
| 27 | -import me.zhyd.oauth.model.AuthResponse; | ||
| 28 | -import me.zhyd.oauth.model.AuthUser; | ||
| 29 | import me.zhyd.oauth.request.AuthRequest; | 25 | import me.zhyd.oauth.request.AuthRequest; |
| 30 | import me.zhyd.oauth.utils.AuthStateUtils; | 26 | import me.zhyd.oauth.utils.AuthStateUtils; |
| 31 | import org.springframework.validation.annotation.Validated; | 27 | import org.springframework.validation.annotation.Validated; |
| @@ -100,16 +96,16 @@ public class SysAuthController { | @@ -100,16 +96,16 @@ public class SysAuthController { | ||
| 100 | return success(SysAuthConvert.INSTANCE.buildMenuTree(menuList)); | 96 | return success(SysAuthConvert.INSTANCE.buildMenuTree(menuList)); |
| 101 | } | 97 | } |
| 102 | 98 | ||
| 103 | - // ========== 三方登陆相关 ========== | 99 | + // ========== 社交登陆相关 ========== |
| 104 | 100 | ||
| 105 | - @GetMapping("/third-login-redirect") | ||
| 106 | - @ApiOperation("三方登陆的跳转") | 101 | + @GetMapping("/social-login-redirect") |
| 102 | + @ApiOperation("社交登陆的跳转") | ||
| 107 | @ApiImplicitParams({ | 103 | @ApiImplicitParams({ |
| 108 | @ApiImplicitParam(name = "type", value = "三方类型", required = true, dataTypeClass = Integer.class), | 104 | @ApiImplicitParam(name = "type", value = "三方类型", required = true, dataTypeClass = Integer.class), |
| 109 | @ApiImplicitParam(name = "redirectUri", value = "回调路径", dataTypeClass = String.class) | 105 | @ApiImplicitParam(name = "redirectUri", value = "回调路径", dataTypeClass = String.class) |
| 110 | }) | 106 | }) |
| 111 | - public CommonResult<String> thirdLoginRedirect(@RequestParam("type") Integer type, | ||
| 112 | - @RequestParam("redirectUri") String redirectUri) { | 107 | + public CommonResult<String> socialLoginRedirect(@RequestParam("type") Integer type, |
| 108 | + @RequestParam("redirectUri") String redirectUri) { | ||
| 113 | // 获得对应的 AuthRequest 实现 | 109 | // 获得对应的 AuthRequest 实现 |
| 114 | AuthRequest authRequest = authRequestFactory.get(SysUserSocialTypeEnum.valueOfType(type).getSource()); | 110 | AuthRequest authRequest = authRequestFactory.get(SysUserSocialTypeEnum.valueOfType(type).getSource()); |
| 115 | // 生成跳转地址 | 111 | // 生成跳转地址 |
| @@ -118,20 +114,30 @@ public class SysAuthController { | @@ -118,20 +114,30 @@ public class SysAuthController { | ||
| 118 | return CommonResult.success(authorizeUri); | 114 | return CommonResult.success(authorizeUri); |
| 119 | } | 115 | } |
| 120 | 116 | ||
| 121 | - @PostMapping("/third-login") | ||
| 122 | - @ApiOperation("三方登陆,使用 code 授权码") | 117 | + @PostMapping("/social-login") |
| 118 | + @ApiOperation("社交登陆,使用 code 授权码") | ||
| 123 | @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 | 119 | @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 |
| 124 | - public CommonResult<SysAuthLoginRespVO> thirdLogin(@RequestBody @Valid SysAuthThirdLoginReqVO reqVO) { | ||
| 125 | - String token = authService.thirdLogin(reqVO, getClientIP(), getUserAgent()); | ||
| 126 | - return null; | 120 | + public CommonResult<SysAuthLoginRespVO> socialLogin(@RequestBody @Valid SysAuthSocialLoginReqVO reqVO) { |
| 121 | + String token = authService.socialLogin(reqVO, getClientIP(), getUserAgent()); | ||
| 122 | + // 返回结果 | ||
| 123 | + return success(SysAuthLoginRespVO.builder().token(token).build()); | ||
| 127 | } | 124 | } |
| 128 | 125 | ||
| 129 | - @RequestMapping("/{type}/callback") | ||
| 130 | - public AuthResponse login(@PathVariable String type, AuthCallback callback) { | ||
| 131 | - AuthRequest authRequest = authRequestFactory.get(type); | ||
| 132 | - AuthResponse<AuthUser> response = authRequest.login(callback); | ||
| 133 | - log.info("【response】= {}", JSONUtil.toJsonStr(response)); | ||
| 134 | - return response; | 126 | + @PostMapping("/social-login2") |
| 127 | + @ApiOperation("社交登陆,使用 code 授权码 + 账号密码") | ||
| 128 | + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 | ||
| 129 | + public CommonResult<SysAuthLoginRespVO> socialLogin2(@RequestBody @Valid SysAuthSocialLogin2ReqVO reqVO) { | ||
| 130 | + String token = authService.socialLogin2(reqVO, getClientIP(), getUserAgent()); | ||
| 131 | + // 返回结果 | ||
| 132 | + return success(SysAuthLoginRespVO.builder().token(token).build()); | ||
| 135 | } | 133 | } |
| 136 | 134 | ||
| 135 | +// @RequestMapping("/{type}/callback") | ||
| 136 | +// public AuthResponse login(@PathVariable String type, AuthCallback callback) { | ||
| 137 | +// AuthRequest authRequest = authRequestFactory.get(type); | ||
| 138 | +// AuthResponse<AuthUser> response = authRequest.login(callback); | ||
| 139 | +// log.info("【response】= {}", JSONUtil.toJsonStr(response)); | ||
| 140 | +// return response; | ||
| 141 | +// } | ||
| 142 | + | ||
| 137 | } | 143 | } |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialLogin2ReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.adminserver.modules.system.enums.user.SysUserSocialTypeEnum; | ||
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 5 | +import io.swagger.annotations.ApiModel; | ||
| 6 | +import io.swagger.annotations.ApiModelProperty; | ||
| 7 | +import lombok.AllArgsConstructor; | ||
| 8 | +import lombok.Builder; | ||
| 9 | +import lombok.Data; | ||
| 10 | +import lombok.NoArgsConstructor; | ||
| 11 | +import org.hibernate.validator.constraints.Length; | ||
| 12 | + | ||
| 13 | +import javax.validation.constraints.NotEmpty; | ||
| 14 | +import javax.validation.constraints.NotNull; | ||
| 15 | +import javax.validation.constraints.Pattern; | ||
| 16 | + | ||
| 17 | +@ApiModel("社交登陆 Request VO,使用 code 授权码 + 账号密码") | ||
| 18 | +@Data | ||
| 19 | +@NoArgsConstructor | ||
| 20 | +@AllArgsConstructor | ||
| 21 | +@Builder | ||
| 22 | +public class SysAuthSocialLogin2ReqVO { | ||
| 23 | + | ||
| 24 | + @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值") | ||
| 25 | + @InEnum(SysUserSocialTypeEnum.class) | ||
| 26 | + @NotNull(message = "社交平台的类型不能为空") | ||
| 27 | + private Integer type; | ||
| 28 | + | ||
| 29 | + @ApiModelProperty(value = "授权码", required = true, example = "1024") | ||
| 30 | + @NotEmpty(message = "授权码不能为空") | ||
| 31 | + private String code; | ||
| 32 | + | ||
| 33 | + @ApiModelProperty(value = "state", required = true, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") | ||
| 34 | + @NotEmpty(message = "state 不能为空") | ||
| 35 | + private String state; | ||
| 36 | + | ||
| 37 | + @ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma") | ||
| 38 | + @NotEmpty(message = "登陆账号不能为空") | ||
| 39 | + @Length(min = 4, max = 16, message = "账号长度为 4-16 位") | ||
| 40 | + @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") | ||
| 41 | + private String username; | ||
| 42 | + | ||
| 43 | + @ApiModelProperty(value = "密码", required = true, example = "buzhidao") | ||
| 44 | + @NotEmpty(message = "密码不能为空") | ||
| 45 | + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") | ||
| 46 | + private String password; | ||
| 47 | + | ||
| 48 | +} |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthThirdLoginReqVO.java renamed to 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; | @@ -14,16 +14,16 @@ import javax.validation.constraints.NotEmpty; | ||
| 14 | import javax.validation.constraints.NotNull; | 14 | import javax.validation.constraints.NotNull; |
| 15 | import javax.validation.constraints.Pattern; | 15 | import javax.validation.constraints.Pattern; |
| 16 | 16 | ||
| 17 | -@ApiModel("三方登陆 Request VO,使用 code 授权码") | 17 | +@ApiModel("社交登陆 Request VO,使用 code 授权码") |
| 18 | @Data | 18 | @Data |
| 19 | @NoArgsConstructor | 19 | @NoArgsConstructor |
| 20 | @AllArgsConstructor | 20 | @AllArgsConstructor |
| 21 | @Builder | 21 | @Builder |
| 22 | -public class SysAuthThirdLoginReqVO { | 22 | +public class SysAuthSocialLoginReqVO { |
| 23 | 23 | ||
| 24 | - @ApiModelProperty(value = "三方平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值") | 24 | + @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 SysUserSocialTypeEnum 枚举值") |
| 25 | @InEnum(SysUserSocialTypeEnum.class) | 25 | @InEnum(SysUserSocialTypeEnum.class) |
| 26 | - @NotNull(message = "三方平台的类型不能为空") | 26 | + @NotNull(message = "社交平台的类型不能为空") |
| 27 | private Integer type; | 27 | private Integer type; |
| 28 | 28 | ||
| 29 | @ApiModelProperty(value = "授权码", required = true, example = "1024") | 29 | @ApiModelProperty(value = "授权码", required = true, example = "1024") |
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; | @@ -2,10 +2,10 @@ package cn.iocoder.yudao.adminserver.modules.system.convert.auth; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthMenuRespVO; | 3 | import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthMenuRespVO; |
| 4 | import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthPermissionInfoRespVO; | 4 | import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthPermissionInfoRespVO; |
| 5 | -import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthThirdLoginReqVO; | 5 | +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLogin2ReqVO; |
| 6 | +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLoginReqVO; | ||
| 6 | import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdatePasswordReqVO; | 7 | import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdatePasswordReqVO; |
| 7 | import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdateReqVO; | 8 | import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile.SysUserProfileUpdateReqVO; |
| 8 | -import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.SysUserCreateReqVO; | ||
| 9 | import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO; | 9 | import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO; |
| 10 | import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO; | 10 | import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO; |
| 11 | import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserDO; | 11 | 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; | @@ -13,10 +13,8 @@ import cn.iocoder.yudao.adminserver.modules.system.enums.permission.MenuIdEnum; | ||
| 13 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 13 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 14 | import cn.iocoder.yudao.framework.security.core.LoginUser; | 14 | import cn.iocoder.yudao.framework.security.core.LoginUser; |
| 15 | import me.zhyd.oauth.model.AuthCallback; | 15 | import me.zhyd.oauth.model.AuthCallback; |
| 16 | -import me.zhyd.oauth.model.AuthUser; | ||
| 17 | import org.mapstruct.Mapper; | 16 | import org.mapstruct.Mapper; |
| 18 | import org.mapstruct.Mapping; | 17 | import org.mapstruct.Mapping; |
| 19 | -import org.mapstruct.Mappings; | ||
| 20 | import org.mapstruct.factory.Mappers; | 18 | import org.mapstruct.factory.Mappers; |
| 21 | import org.slf4j.LoggerFactory; | 19 | import org.slf4j.LoggerFactory; |
| 22 | 20 | ||
| @@ -45,7 +43,9 @@ public interface SysAuthConvert { | @@ -45,7 +43,9 @@ public interface SysAuthConvert { | ||
| 45 | 43 | ||
| 46 | LoginUser convert(SysUserProfileUpdatePasswordReqVO reqVO); | 44 | LoginUser convert(SysUserProfileUpdatePasswordReqVO reqVO); |
| 47 | 45 | ||
| 48 | - AuthCallback convert(SysAuthThirdLoginReqVO bean); | 46 | + AuthCallback convert(SysAuthSocialLoginReqVO bean); |
| 47 | + | ||
| 48 | + AuthCallback convert(SysAuthSocialLogin2ReqVO bean); | ||
| 49 | 49 | ||
| 50 | /** | 50 | /** |
| 51 | * 将菜单列表,构建成菜单树 | 51 | * 将菜单列表,构建成菜单树 |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/user/SysUserSocialDO.java renamed to yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/user/SysSocialUserDO.java
| 1 | package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user; | 1 | package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.adminserver.modules.system.enums.user.SysUserSocialTypeEnum; | ||
| 4 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | 3 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 5 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 4 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 6 | import com.baomidou.mybatisplus.annotation.TableId; | 5 | import com.baomidou.mybatisplus.annotation.TableId; |
| @@ -8,18 +7,18 @@ import com.baomidou.mybatisplus.annotation.TableName; | @@ -8,18 +7,18 @@ import com.baomidou.mybatisplus.annotation.TableName; | ||
| 8 | import lombok.*; | 7 | import lombok.*; |
| 9 | 8 | ||
| 10 | /** | 9 | /** |
| 11 | - * 三方登陆信息 | ||
| 12 | - * 通过 {@link SysUserSocialDO#getUserId()} 关联到对应的 {@link SysUserDO} | 10 | + * 社交用户 |
| 11 | + * 通过 {@link SysSocialUserDO#getUserId()} 关联到对应的 {@link SysUserDO} | ||
| 13 | * | 12 | * |
| 14 | * @author weir | 13 | * @author weir |
| 15 | */ | 14 | */ |
| 16 | -@TableName(value = "sys_user_social", autoResultMap = true) | 15 | +@TableName(value = "sys_social_user", autoResultMap = true) |
| 17 | @Data | 16 | @Data |
| 18 | @EqualsAndHashCode(callSuper = true) | 17 | @EqualsAndHashCode(callSuper = true) |
| 19 | @Builder | 18 | @Builder |
| 20 | @NoArgsConstructor | 19 | @NoArgsConstructor |
| 21 | @AllArgsConstructor | 20 | @AllArgsConstructor |
| 22 | -public class SysUserSocialDO extends BaseDO { | 21 | +public class SysSocialUserDO extends BaseDO { |
| 23 | 22 | ||
| 24 | /** | 23 | /** |
| 25 | * 自增主键 | 24 | * 自增主键 |
| @@ -27,7 +26,7 @@ public class SysUserSocialDO extends BaseDO { | @@ -27,7 +26,7 @@ public class SysUserSocialDO extends BaseDO { | ||
| 27 | @TableId | 26 | @TableId |
| 28 | private Long id; | 27 | private Long id; |
| 29 | /** | 28 | /** |
| 30 | - * 用户编号 | 29 | + * 关联的用户编号 |
| 31 | */ | 30 | */ |
| 32 | private Long userId; | 31 | private Long userId; |
| 33 | /** | 32 | /** |
| @@ -38,20 +37,22 @@ public class SysUserSocialDO extends BaseDO { | @@ -38,20 +37,22 @@ public class SysUserSocialDO extends BaseDO { | ||
| 38 | private Integer userType; | 37 | private Integer userType; |
| 39 | 38 | ||
| 40 | /** | 39 | /** |
| 41 | - * 三方平台的类型 | 40 | + * 社交平台的类型 |
| 41 | + * | ||
| 42 | + * 枚举 {@link UserTypeEnum} | ||
| 42 | */ | 43 | */ |
| 43 | - private SysUserSocialTypeEnum type; | 44 | + private Integer type; |
| 44 | 45 | ||
| 45 | /** | 46 | /** |
| 46 | - * 三方 openid | 47 | + * 社交 openid |
| 47 | */ | 48 | */ |
| 48 | private String openid; | 49 | private String openid; |
| 49 | /** | 50 | /** |
| 50 | - * 三方 token | 51 | + * 社交 token |
| 51 | */ | 52 | */ |
| 52 | private String token; | 53 | private String token; |
| 53 | /** | 54 | /** |
| 54 | - * 三方的全局编号 | 55 | + * 社交的全局编号 |
| 55 | * | 56 | * |
| 56 | * 例如说,微信平台的 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html | 57 | * 例如说,微信平台的 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html |
| 57 | * 如果没有 unionId 的平台,直接使用 openid 作为该字段的值 | 58 | * 如果没有 unionId 的平台,直接使用 openid 作为该字段的值 |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/social/SysSysUserSocialMapper.java
| 1 | package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social; | 1 | package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserSocialDO; | 3 | +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysSocialUserDO; |
| 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | import org.apache.ibatis.annotations.Mapper; | 5 | import org.apache.ibatis.annotations.Mapper; |
| 6 | 6 | ||
| 7 | @Mapper | 7 | @Mapper |
| 8 | -public interface SysSysUserSocialMapper extends BaseMapperX<SysUserSocialDO> { | 8 | +public interface SysSysUserSocialMapper extends BaseMapperX<SysSocialUserDO> { |
| 9 | 9 | ||
| 10 | 10 | ||
| 11 | } | 11 | } |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/social/SysUserSocialMapper.java
| 1 | package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social; | 1 | package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserSocialDO; | 3 | +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysSocialUserDO; |
| 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 5 | import org.apache.ibatis.annotations.Mapper; | 5 | import org.apache.ibatis.annotations.Mapper; |
| 6 | 6 | ||
| 7 | @Mapper | 7 | @Mapper |
| 8 | -public interface SysUserSocialMapper extends BaseMapperX<SysUserSocialDO> { | 8 | +public interface SysUserSocialMapper extends BaseMapperX<SysSocialUserDO> { |
| 9 | 9 | ||
| 10 | 10 | ||
| 11 | } | 11 | } |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysSocialUserMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.user; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysSocialUserDO; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 5 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 6 | +import org.apache.ibatis.annotations.Mapper; | ||
| 7 | + | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +@Mapper | ||
| 11 | +public interface SysSocialUserMapper extends BaseMapperX<SysSocialUserDO> { | ||
| 12 | + | ||
| 13 | + default List<SysSocialUserDO> selectListByTypeAndUnionId(Integer userType, Integer type, String unionId) { | ||
| 14 | + return selectList(new QueryWrapper<SysSocialUserDO>().eq("user_type", userType) | ||
| 15 | + .eq("type", type).eq("union_id", unionId)); | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | +} |
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; | @@ -2,6 +2,9 @@ package cn.iocoder.yudao.adminserver.modules.system.dal.redis; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine; | 3 | import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine; |
| 4 | import cn.iocoder.yudao.framework.security.core.LoginUser; | 4 | import cn.iocoder.yudao.framework.security.core.LoginUser; |
| 5 | +import me.zhyd.oauth.model.AuthUser; | ||
| 6 | + | ||
| 7 | +import java.time.Duration; | ||
| 5 | 8 | ||
| 6 | import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING; | 9 | import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING; |
| 7 | 10 | ||
| @@ -20,4 +23,8 @@ public interface SysRedisKeyConstants { | @@ -20,4 +23,8 @@ public interface SysRedisKeyConstants { | ||
| 20 | "captcha_code:%s", // 参数为 uuid | 23 | "captcha_code:%s", // 参数为 uuid |
| 21 | STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); | 24 | STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); |
| 22 | 25 | ||
| 26 | + RedisKeyDefine AUTH_SOCIAL_USER = new RedisKeyDefine("认证的三方用户", | ||
| 27 | + "auth_social_user:%d:%s", // 参数为 type,code | ||
| 28 | + STRING, AuthUser.class, Duration.ofDays(1)); | ||
| 29 | + | ||
| 23 | } | 30 | } |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/auth/SysAuthSocialUserRedisDAO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.adminserver.modules.system.dal.redis.auth; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 4 | +import me.zhyd.oauth.model.AuthCallback; | ||
| 5 | +import me.zhyd.oauth.model.AuthUser; | ||
| 6 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 7 | +import org.springframework.stereotype.Repository; | ||
| 8 | + | ||
| 9 | +import javax.annotation.Resource; | ||
| 10 | + | ||
| 11 | +import static cn.iocoder.yudao.adminserver.modules.system.dal.redis.SysRedisKeyConstants.AUTH_SOCIAL_USER; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * 社交 {@link me.zhyd.oauth.model.AuthUser} 的 RedisDAO | ||
| 15 | + * | ||
| 16 | + * @author 芋道源码 | ||
| 17 | + */ | ||
| 18 | +@Repository | ||
| 19 | +public class SysAuthSocialUserRedisDAO { | ||
| 20 | + | ||
| 21 | + @Resource | ||
| 22 | + private StringRedisTemplate stringRedisTemplate; | ||
| 23 | + | ||
| 24 | + public AuthUser get(Integer type, AuthCallback authCallback) { | ||
| 25 | + String redisKey = formatKey(type, authCallback.getCode()); | ||
| 26 | + return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), AuthUser.class); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public void set(Integer type, AuthCallback authCallback, AuthUser authUser) { | ||
| 30 | + String redisKey = formatKey(type, authCallback.getCode()); | ||
| 31 | + stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(authUser), AUTH_SOCIAL_USER.getTimeout()); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + private static String formatKey(Integer type, String code) { | ||
| 35 | + return String.format(AUTH_SOCIAL_USER.getKeyTemplate(), type, code); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | +} |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/auth/SysLoginUserRedisDAO.java
| @@ -22,7 +22,7 @@ public class SysLoginUserRedisDAO { | @@ -22,7 +22,7 @@ public class SysLoginUserRedisDAO { | ||
| 22 | @Resource | 22 | @Resource |
| 23 | private StringRedisTemplate stringRedisTemplate; | 23 | private StringRedisTemplate stringRedisTemplate; |
| 24 | @Resource | 24 | @Resource |
| 25 | - private SysUserSessionService sysUserSessionService; | 25 | + private SysUserSessionService sysUserSessionService; // TODO 芋艿:得看看怎么拿出去 |
| 26 | 26 | ||
| 27 | public LoginUser get(String sessionId) { | 27 | public LoginUser get(String sessionId) { |
| 28 | String redisKey = formatKey(sessionId); | 28 | String redisKey = formatKey(sessionId); |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java
| 1 | package cn.iocoder.yudao.adminserver.modules.system.enums; | 1 | package cn.iocoder.yudao.adminserver.modules.system.enums; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.adminserver.modules.tool.framework.errorcode.config.ErrorCodeConfiguration; | ||
| 3 | import cn.iocoder.yudao.framework.common.exception.ErrorCode; | 4 | import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
| 4 | 5 | ||
| 5 | /** | 6 | /** |
| @@ -15,6 +16,8 @@ public interface SysErrorCodeConstants { | @@ -15,6 +16,8 @@ public interface SysErrorCodeConstants { | ||
| 15 | ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1002000002, "登录失败"); // 登陆失败的兜底,位置原因 | 16 | ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1002000002, "登录失败"); // 登陆失败的兜底,位置原因 |
| 16 | ErrorCode AUTH_LOGIN_CAPTCHA_NOT_FOUND = new ErrorCode(1002000003, "验证码不存在"); | 17 | ErrorCode AUTH_LOGIN_CAPTCHA_NOT_FOUND = new ErrorCode(1002000003, "验证码不存在"); |
| 17 | ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1002000004, "验证码不正确"); | 18 | ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1002000004, "验证码不正确"); |
| 19 | + ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1002000005, "未绑定账号,需要进行绑定"); | ||
| 20 | + ErrorCode AUTH_THIRD_OAUTH_FAILURE = new ErrorCode(1002000006, "三方授权失败,原因是:{}"); | ||
| 18 | 21 | ||
| 19 | // ========== TOKEN 模块 1002001000 ========== | 22 | // ========== TOKEN 模块 1002001000 ========== |
| 20 | ErrorCode TOKEN_EXPIRED = new ErrorCode(1002001000, "Token 已经过期"); | 23 | ErrorCode TOKEN_EXPIRED = new ErrorCode(1002001000, "Token 已经过期"); |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/logger/SysLoginLogTypeEnum.java
| @@ -11,6 +11,7 @@ import lombok.Getter; | @@ -11,6 +11,7 @@ import lombok.Getter; | ||
| 11 | public enum SysLoginLogTypeEnum { | 11 | public enum SysLoginLogTypeEnum { |
| 12 | 12 | ||
| 13 | LOGIN_USERNAME(100), // 使用账号登录 | 13 | LOGIN_USERNAME(100), // 使用账号登录 |
| 14 | + LOGIN_SOCIAL(101), // 使用社交登陆 | ||
| 14 | 15 | ||
| 15 | LOGOUT_SELF(200), // 自己主动登出 | 16 | LOGOUT_SELF(200), // 自己主动登出 |
| 16 | LOGOUT_TIMEOUT(201), // 超时登出 | 17 | LOGOUT_TIMEOUT(201), // 超时登出 |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/user/SysUserSocialTypeEnum.java
| 1 | package cn.iocoder.yudao.adminserver.modules.system.enums.user; | 1 | package cn.iocoder.yudao.adminserver.modules.system.enums.user; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.util.ArrayUtil; | 3 | import cn.hutool.core.util.ArrayUtil; |
| 4 | -import cn.iocoder.yudao.adminserver.modules.system.enums.errorcode.SysErrorCodeTypeEnum; | ||
| 5 | import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | 4 | import cn.iocoder.yudao.framework.common.core.IntArrayValuable; |
| 6 | -import com.fasterxml.jackson.annotation.JsonCreator; | ||
| 7 | -import jodd.util.ArraysUtil; | ||
| 8 | import lombok.AllArgsConstructor; | 5 | import lombok.AllArgsConstructor; |
| 9 | import lombok.Getter; | 6 | import lombok.Getter; |
| 10 | 7 | ||
| 11 | import java.util.Arrays; | 8 | import java.util.Arrays; |
| 12 | 9 | ||
| 13 | /** | 10 | /** |
| 14 | - * 用户的三方平台的类型枚举 | 11 | + * 用户的社交平台的类型枚举 |
| 15 | * | 12 | * |
| 16 | * @author 芋道源码 | 13 | * @author 芋道源码 |
| 17 | */ | 14 | */ |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthService.java
| 1 | package cn.iocoder.yudao.adminserver.modules.system.service.auth; | 1 | package cn.iocoder.yudao.adminserver.modules.system.service.auth; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthThirdLoginReqVO; | 3 | +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLogin2ReqVO; |
| 4 | +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLoginReqVO; | ||
| 4 | import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; | 5 | import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; |
| 5 | import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthLoginReqVO; | 6 | import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthLoginReqVO; |
| 6 | 7 | ||
| @@ -24,13 +25,23 @@ public interface SysAuthService extends SecurityAuthFrameworkService { | @@ -24,13 +25,23 @@ public interface SysAuthService extends SecurityAuthFrameworkService { | ||
| 24 | String login(SysAuthLoginReqVO reqVO, String userIp, String userAgent); | 25 | String login(SysAuthLoginReqVO reqVO, String userIp, String userAgent); |
| 25 | 26 | ||
| 26 | /** | 27 | /** |
| 27 | - * 三方登陆用户,使用 code 授权码 | 28 | + * 社交登陆用户,使用 code 授权码 |
| 28 | * | 29 | * |
| 29 | * @param reqVO 登陆信息 | 30 | * @param reqVO 登陆信息 |
| 30 | * @param userIp 用户 IP | 31 | * @param userIp 用户 IP |
| 31 | * @param userAgent 用户 UA | 32 | * @param userAgent 用户 UA |
| 32 | * @return 身份令牌,使用 JWT 方式 | 33 | * @return 身份令牌,使用 JWT 方式 |
| 33 | */ | 34 | */ |
| 34 | - String thirdLogin(SysAuthThirdLoginReqVO reqVO, String userIp, String userAgent); | 35 | + String socialLogin(SysAuthSocialLoginReqVO reqVO, String userIp, String userAgent); |
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * 社交登陆用户,使用 code 授权码 + 账号密码 | ||
| 39 | + * | ||
| 40 | + * @param reqVO 登陆信息 | ||
| 41 | + * @param userIp 用户 IP | ||
| 42 | + * @param userAgent 用户 UA | ||
| 43 | + * @return 身份令牌,使用 JWT 方式 | ||
| 44 | + */ | ||
| 45 | + String socialLogin2(SysAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent); | ||
| 35 | 46 | ||
| 36 | } | 47 | } |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
| 1 | package cn.iocoder.yudao.adminserver.modules.system.service.auth.impl; | 1 | package cn.iocoder.yudao.adminserver.modules.system.service.auth.impl; |
| 2 | 2 | ||
| 3 | -import cn.hutool.json.JSONUtil; | ||
| 4 | -import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthThirdLoginReqVO; | 3 | +import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.util.StrUtil; | ||
| 5 | +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLogin2ReqVO; | ||
| 6 | +import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLoginReqVO; | ||
| 7 | +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysSocialUserDO; | ||
| 8 | +import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.user.SysSocialUserMapper; | ||
| 9 | +import cn.iocoder.yudao.adminserver.modules.system.dal.redis.auth.SysAuthSocialUserRedisDAO; | ||
| 5 | import cn.iocoder.yudao.adminserver.modules.system.enums.user.SysUserSocialTypeEnum; | 10 | import cn.iocoder.yudao.adminserver.modules.system.enums.user.SysUserSocialTypeEnum; |
| 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 11 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 12 | +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 7 | import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; | 13 | import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; |
| 8 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 14 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 9 | import cn.iocoder.yudao.framework.security.core.LoginUser; | 15 | import cn.iocoder.yudao.framework.security.core.LoginUser; |
| @@ -40,6 +46,8 @@ import org.springframework.stereotype.Service; | @@ -40,6 +46,8 @@ import org.springframework.stereotype.Service; | ||
| 40 | import org.springframework.util.Assert; | 46 | import org.springframework.util.Assert; |
| 41 | 47 | ||
| 42 | import javax.annotation.Resource; | 48 | import javax.annotation.Resource; |
| 49 | +import java.util.List; | ||
| 50 | +import java.util.Objects; | ||
| 43 | import java.util.Set; | 51 | import java.util.Set; |
| 44 | 52 | ||
| 45 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 53 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| @@ -58,6 +66,7 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -58,6 +66,7 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 58 | @Resource | 66 | @Resource |
| 59 | @Lazy // 延迟加载,因为存在相互依赖的问题 | 67 | @Lazy // 延迟加载,因为存在相互依赖的问题 |
| 60 | private AuthenticationManager authenticationManager; | 68 | private AuthenticationManager authenticationManager; |
| 69 | + | ||
| 61 | @Resource | 70 | @Resource |
| 62 | private SysUserService userService; | 71 | private SysUserService userService; |
| 63 | @Resource | 72 | @Resource |
| @@ -70,6 +79,11 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -70,6 +79,11 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 70 | private SysUserSessionService userSessionService; | 79 | private SysUserSessionService userSessionService; |
| 71 | 80 | ||
| 72 | @Resource | 81 | @Resource |
| 82 | + private SysAuthSocialUserRedisDAO authSocialUserRedisDAO; | ||
| 83 | + @Resource | ||
| 84 | + private SysSocialUserMapper socialUserMapper; | ||
| 85 | + | ||
| 86 | + @Resource | ||
| 73 | private AuthRequestFactory authRequestFactory; | 87 | private AuthRequestFactory authRequestFactory; |
| 74 | 88 | ||
| 75 | @Override | 89 | @Override |
| @@ -109,24 +123,6 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -109,24 +123,6 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 109 | return userSessionService.createUserSession(loginUser, userIp, userAgent); | 123 | return userSessionService.createUserSession(loginUser, userIp, userAgent); |
| 110 | } | 124 | } |
| 111 | 125 | ||
| 112 | - @Override | ||
| 113 | - public String thirdLogin(SysAuthThirdLoginReqVO reqVO, String userIp, String userAgent) { | ||
| 114 | - // 使用 code 授权码,进行登陆 | ||
| 115 | - AuthRequest authRequest = authRequestFactory.get(SysUserSocialTypeEnum.valueOfType(reqVO.getType()).getSource()); | ||
| 116 | - AuthCallback authCallback = SysAuthConvert.INSTANCE.convert(reqVO); | ||
| 117 | - AuthResponse<?> authResponse = authRequest.login(authCallback); | ||
| 118 | - log.info("[thirdLogin][请求三方平台 type({}) request({}) response({})]", reqVO.getType(), JsonUtils.toJsonString(authCallback), | ||
| 119 | - JsonUtils.toJsonString(authResponse)); | ||
| 120 | - if (!authResponse.ok()) { | ||
| 121 | - throw new RuntimeException(""); // TODO 芋艿:补全 | ||
| 122 | - } | ||
| 123 | - AuthUser authUser = (AuthUser) authResponse.getData(); | ||
| 124 | - | ||
| 125 | - // 查找到对应的 | ||
| 126 | - | ||
| 127 | - return null; | ||
| 128 | - } | ||
| 129 | - | ||
| 130 | private void verifyCaptcha(String username, String captchaUUID, String captchaCode) { | 126 | private void verifyCaptcha(String username, String captchaUUID, String captchaCode) { |
| 131 | String code = captchaService.getCaptchaCode(captchaUUID); | 127 | String code = captchaService.getCaptchaCode(captchaUUID); |
| 132 | // 验证码不存在 | 128 | // 验证码不存在 |
| @@ -191,6 +187,124 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -191,6 +187,124 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 191 | } | 187 | } |
| 192 | 188 | ||
| 193 | @Override | 189 | @Override |
| 190 | + public String socialLogin(SysAuthSocialLoginReqVO reqVO, String userIp, String userAgent) { | ||
| 191 | + // 使用 code 授权码,进行登陆 | ||
| 192 | + AuthCallback authCallback = SysAuthConvert.INSTANCE.convert(reqVO); | ||
| 193 | + AuthUser authUser = this.obtainAuthUserFromCache(reqVO.getType(), authCallback); | ||
| 194 | + | ||
| 195 | + // 如果未绑定 SysSocialUserDO 用户,则无法自动登陆,进行报错 | ||
| 196 | + String unionId = getAuthUserUnionId(authUser); | ||
| 197 | + List<SysSocialUserDO> socialUsers = socialUserMapper.selectListByTypeAndUnionId(UserTypeEnum.ADMIN.getValue(), | ||
| 198 | + reqVO.getType(), unionId); | ||
| 199 | + if (CollUtil.isEmpty(socialUsers)) { | ||
| 200 | + throw exception(AUTH_THIRD_LOGIN_NOT_BIND); | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + // 使用账号密码,进行登陆。 | ||
| 204 | + SysUserDO user = userService.getUser(socialUsers.get(0).getUserId()); | ||
| 205 | + if (user == null) { | ||
| 206 | + throw exception(USER_NOT_EXISTS); | ||
| 207 | + } | ||
| 208 | + LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); | ||
| 209 | + // TODO 芋艿:需要改造下,增加各种登陆方式 | ||
| 210 | + loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表 | ||
| 211 | + | ||
| 212 | + // 保存社交用户 | ||
| 213 | + this.saveSocialUser(reqVO.getType(), socialUsers, loginUser.getId(), authUser); | ||
| 214 | + | ||
| 215 | + // 缓存登陆用户到 Redis 中,返回 sessionId 编号 | ||
| 216 | + return userSessionService.createUserSession(loginUser, userIp, userAgent); | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + @Override | ||
| 220 | + public String socialLogin2(SysAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent) { | ||
| 221 | + // 使用 code 授权码,进行登陆 | ||
| 222 | + AuthCallback authCallback = SysAuthConvert.INSTANCE.convert(reqVO); | ||
| 223 | + AuthUser authUser = this.obtainAuthUserFromCache(reqVO.getType(), authCallback); | ||
| 224 | + | ||
| 225 | + // 查询社交对应的 SysSocialUserDO 用户 | ||
| 226 | + String unionId = getAuthUserUnionId(authUser); | ||
| 227 | + List<SysSocialUserDO> socialUsers = socialUserMapper.selectListByTypeAndUnionId(UserTypeEnum.ADMIN.getValue(), | ||
| 228 | + reqVO.getType(), unionId); | ||
| 229 | + | ||
| 230 | + // 使用账号密码,进行登陆。 | ||
| 231 | + LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword()); // TODO 芋艿:需要改造下,增加各种登陆方式 | ||
| 232 | + loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表 | ||
| 233 | + | ||
| 234 | + // 保存社交用户 | ||
| 235 | + this.saveSocialUser(reqVO.getType(), socialUsers, loginUser.getId(), authUser); | ||
| 236 | + | ||
| 237 | + // 缓存登陆用户到 Redis 中,返回 sessionId 编号 | ||
| 238 | + return userSessionService.createUserSession(loginUser, userIp, userAgent); | ||
| 239 | + } | ||
| 240 | + | ||
| 241 | + private static String getAuthUserUnionId(AuthUser authUser) { | ||
| 242 | + return StrUtil.blankToDefault(authUser.getToken().getUnionId(), authUser.getUuid()); | ||
| 243 | + } | ||
| 244 | + | ||
| 245 | + private AuthUser obtainAuthUserFromCache(Integer type, AuthCallback authCallback) { | ||
| 246 | + // 从缓存中获取 | ||
| 247 | + AuthUser authUser = authSocialUserRedisDAO.get(type, authCallback); | ||
| 248 | + if (authUser != null) { | ||
| 249 | + return authUser; | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + // 请求获取 | ||
| 253 | + authUser = this.obtainAuthUser(type, authCallback); | ||
| 254 | + authSocialUserRedisDAO.set(type, authCallback, authUser); | ||
| 255 | + return authUser; | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + private AuthUser obtainAuthUser(Integer type, AuthCallback authCallback) { | ||
| 259 | + AuthRequest authRequest = authRequestFactory.get(SysUserSocialTypeEnum.valueOfType(type).getSource()); | ||
| 260 | + AuthResponse<?> authResponse = authRequest.login(authCallback); | ||
| 261 | + log.info("[obtainAuthUser][请求三方平台 type({}) request({}) response({})]", type, JsonUtils.toJsonString(authCallback), | ||
| 262 | + JsonUtils.toJsonString(authResponse)); | ||
| 263 | + if (!authResponse.ok()) { | ||
| 264 | + throw exception(AUTH_THIRD_OAUTH_FAILURE, authResponse.getMsg()); | ||
| 265 | + } | ||
| 266 | + return (AuthUser) authResponse.getData(); | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + /** | ||
| 270 | + * 保存社交用户 | ||
| 271 | + * | ||
| 272 | + * @param socialUsers 已存在的社交用户列表 | ||
| 273 | + * @param userId 绑定的用户编号 | ||
| 274 | + * @param authUser 需要保存的社交用户信息 | ||
| 275 | + */ | ||
| 276 | + private void saveSocialUser(Integer type, List<SysSocialUserDO> socialUsers, Long userId, AuthUser authUser) { | ||
| 277 | + // 逻辑一:如果 socialUsers 指定的 userId 改变,需要进行更新 | ||
| 278 | + // 例如说,一个微信 unionId 对应了多个社交账号,结果其中有个关联了新的 userId,则其它也要跟着修改 | ||
| 279 | + // 考虑到 socialUsers 一般比较少,直接 for 循环更新即可 | ||
| 280 | + socialUsers.forEach(socialUser -> { | ||
| 281 | + if (Objects.equals(socialUser.getUserId(), userId)) { | ||
| 282 | + return; | ||
| 283 | + } | ||
| 284 | + socialUserMapper.updateById(new SysSocialUserDO().setUserId(socialUser.getUserId()).setUserId(userId)); | ||
| 285 | + }); | ||
| 286 | + | ||
| 287 | + // 逻辑二:如果 authUser 不存在于 socialUsers 中,则进行新增;否则,进行更新 | ||
| 288 | + SysSocialUserDO saveSocialUser = CollUtil.findOneByField(socialUsers, "openid", authUser.getUuid()); | ||
| 289 | + if (saveSocialUser == null) { | ||
| 290 | + saveSocialUser = new SysSocialUserDO(); | ||
| 291 | + saveSocialUser.setUserId(userId).setUserType(UserTypeEnum.ADMIN.getValue()); | ||
| 292 | + saveSocialUser.setType(type).setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()) | ||
| 293 | + .setUnionId(getAuthUserUnionId(authUser)).setRawTokenInfo(JsonUtils.toJsonString(authUser.getToken())); | ||
| 294 | + saveSocialUser.setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()) | ||
| 295 | + .setRawUserInfo(JsonUtils.toJsonString(authUser.getRawUserInfo())); | ||
| 296 | + socialUserMapper.insert(saveSocialUser); | ||
| 297 | + } else { | ||
| 298 | + saveSocialUser = new SysSocialUserDO().setId(saveSocialUser.getId()); | ||
| 299 | + saveSocialUser.setToken(authUser.getToken().getAccessToken()).setUnionId(getAuthUserUnionId(authUser)) | ||
| 300 | + .setRawTokenInfo(JsonUtils.toJsonString(authUser.getToken())); | ||
| 301 | + saveSocialUser.setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()) | ||
| 302 | + .setRawUserInfo(JsonUtils.toJsonString(authUser.getRawUserInfo())); | ||
| 303 | + socialUserMapper.updateById(saveSocialUser); | ||
| 304 | + } | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + @Override | ||
| 194 | public void logout(String token) { | 308 | public void logout(String token) { |
| 195 | // 查询用户信息 | 309 | // 查询用户信息 |
| 196 | LoginUser loginUser = userSessionService.getLoginUser(token); | 310 | LoginUser loginUser = userSessionService.getLoginUser(token); |
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; | @@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.hutool.core.io.IoUtil; | 4 | import cn.hutool.core.io.IoUtil; |
| 5 | import cn.hutool.core.util.IdUtil; | 5 | import cn.hutool.core.util.IdUtil; |
| 6 | import cn.hutool.core.util.StrUtil; | 6 | import cn.hutool.core.util.StrUtil; |
| 7 | -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysUserSocialDO; | 7 | +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.user.SysSocialUserDO; |
| 8 | import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social.SysUserSocialMapper; | 8 | import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social.SysUserSocialMapper; |
| 9 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 9 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 10 | import cn.iocoder.yudao.framework.common.exception.ServiceException; | 10 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| @@ -80,7 +80,7 @@ public class SysUserServiceImpl implements SysUserService { | @@ -80,7 +80,7 @@ public class SysUserServiceImpl implements SysUserService { | ||
| 80 | 80 | ||
| 81 | @Override | 81 | @Override |
| 82 | public Long bindSocialUSer(Long sysUserId, String socialUSerId) { | 82 | public Long bindSocialUSer(Long sysUserId, String socialUSerId) { |
| 83 | - SysUserSocialDO userSocialDO = new SysUserSocialDO(); | 83 | + SysSocialUserDO userSocialDO = new SysSocialUserDO(); |
| 84 | userSocialDO.setUserId(sysUserId); | 84 | userSocialDO.setUserId(sysUserId); |
| 85 | // userSocialDO.setSocialUserId(socialUSerId); | 85 | // userSocialDO.setSocialUserId(socialUSerId); |
| 86 | userSocialMapper.insert(userSocialDO); | 86 | userSocialMapper.insert(userSocialDO); |
yudao-admin-ui/src/api/login.js
| @@ -39,18 +39,18 @@ export function getCodeImg() { | @@ -39,18 +39,18 @@ export function getCodeImg() { | ||
| 39 | }) | 39 | }) |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | -// 三方登陆的跳转 | ||
| 43 | -export function thirdLoginRedirect(type, redirectUri) { | 42 | +// 社交登陆的跳转 |
| 43 | +export function socialLoginRedirect(type, redirectUri) { | ||
| 44 | return request({ | 44 | return request({ |
| 45 | - url: '/third-login-redirect?type=' + type + '&redirectUri=' + redirectUri, | 45 | + url: '/social-login-redirect?type=' + type + '&redirectUri=' + redirectUri, |
| 46 | method: 'get' | 46 | method: 'get' |
| 47 | }) | 47 | }) |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | -// 三方登陆,使用 code 授权码 | ||
| 51 | -export function thirdLogin(type, code, state) { | 50 | +// 社交登陆,使用 code 授权码 |
| 51 | +export function socialLogin(type, code, state) { | ||
| 52 | return request({ | 52 | return request({ |
| 53 | - url: '/third-login', | 53 | + url: '/social-login', |
| 54 | method: 'post', | 54 | method: 'post', |
| 55 | data: { | 55 | data: { |
| 56 | type, | 56 | type, |
| @@ -59,3 +59,18 @@ export function thirdLogin(type, code, state) { | @@ -59,3 +59,18 @@ export function thirdLogin(type, code, state) { | ||
| 59 | } | 59 | } |
| 60 | }) | 60 | }) |
| 61 | } | 61 | } |
| 62 | + | ||
| 63 | +// 社交登陆,使用 code 授权码 + + 账号密码 | ||
| 64 | +export function socialLogin2(type, code, state, username, password) { | ||
| 65 | + return request({ | ||
| 66 | + url: '/social-login2', | ||
| 67 | + method: 'post', | ||
| 68 | + data: { | ||
| 69 | + type, | ||
| 70 | + code, | ||
| 71 | + state, | ||
| 72 | + username, | ||
| 73 | + password | ||
| 74 | + } | ||
| 75 | + }) | ||
| 76 | +} |
yudao-admin-ui/src/permission.js
| @@ -7,7 +7,7 @@ import { getToken } from '@/utils/auth' | @@ -7,7 +7,7 @@ import { getToken } from '@/utils/auth' | ||
| 7 | 7 | ||
| 8 | NProgress.configure({ showSpinner: false }) | 8 | NProgress.configure({ showSpinner: false }) |
| 9 | 9 | ||
| 10 | -const whiteList = ['/login', '/third-login', '/auth-redirect', '/bind', '/register', '/oauthLogin/gitee'] | 10 | +const whiteList = ['/login', '/social-login', '/auth-redirect', '/bind', '/register', '/oauthLogin/gitee'] |
| 11 | 11 | ||
| 12 | router.beforeEach((to, from, next) => { | 12 | router.beforeEach((to, from, next) => { |
| 13 | NProgress.start() | 13 | NProgress.start() |
yudao-admin-ui/src/router/index.js
| @@ -44,8 +44,8 @@ export const constantRoutes = [ | @@ -44,8 +44,8 @@ export const constantRoutes = [ | ||
| 44 | hidden: true | 44 | hidden: true |
| 45 | }, | 45 | }, |
| 46 | { | 46 | { |
| 47 | - path: '/third-login', | ||
| 48 | - component: (resolve) => require(['@/views/thirdLogin'], resolve), | 47 | + path: '/social-login', |
| 48 | + component: (resolve) => require(['@/views/socialLogin'], resolve), | ||
| 49 | hidden: true | 49 | hidden: true |
| 50 | }, | 50 | }, |
| 51 | { | 51 | { |
yudao-admin-ui/src/store/modules/user.js
| 1 | -import { login, logout, getInfo } from '@/api/login' | 1 | +import {login, logout, getInfo, socialLogin, socialLogin2} from '@/api/login' |
| 2 | import { getToken, setToken, removeToken } from '@/utils/auth' | 2 | import { getToken, setToken, removeToken } from '@/utils/auth' |
| 3 | 3 | ||
| 4 | const user = { | 4 | const user = { |
| @@ -47,6 +47,42 @@ const user = { | @@ -47,6 +47,42 @@ const user = { | ||
| 47 | }) | 47 | }) |
| 48 | }, | 48 | }, |
| 49 | 49 | ||
| 50 | + // 社交登陆 | ||
| 51 | + SocialLogin({ commit }, userInfo) { | ||
| 52 | + const code = userInfo.code | ||
| 53 | + const state = userInfo.state | ||
| 54 | + const type = userInfo.type | ||
| 55 | + return new Promise((resolve, reject) => { | ||
| 56 | + socialLogin(type, code, state).then(res => { | ||
| 57 | + res = res.data; | ||
| 58 | + setToken(res.token) | ||
| 59 | + commit('SET_TOKEN', res.token) | ||
| 60 | + resolve() | ||
| 61 | + }).catch(error => { | ||
| 62 | + reject(error) | ||
| 63 | + }) | ||
| 64 | + }) | ||
| 65 | + }, | ||
| 66 | + | ||
| 67 | + // 社交登陆 | ||
| 68 | + SocialLogin2({ commit }, userInfo) { | ||
| 69 | + const code = userInfo.code | ||
| 70 | + const state = userInfo.state | ||
| 71 | + const type = userInfo.type | ||
| 72 | + const username = userInfo.username.trim() | ||
| 73 | + const password = userInfo.password | ||
| 74 | + return new Promise((resolve, reject) => { | ||
| 75 | + socialLogin2(type, code, state, username, password).then(res => { | ||
| 76 | + res = res.data; | ||
| 77 | + setToken(res.token) | ||
| 78 | + commit('SET_TOKEN', res.token) | ||
| 79 | + resolve() | ||
| 80 | + }).catch(error => { | ||
| 81 | + reject(error) | ||
| 82 | + }) | ||
| 83 | + }) | ||
| 84 | + }, | ||
| 85 | + | ||
| 50 | // 获取用户信息 | 86 | // 获取用户信息 |
| 51 | GetInfo({ commit, state }) { | 87 | GetInfo({ commit, state }) { |
| 52 | return new Promise((resolve, reject) => { | 88 | return new Promise((resolve, reject) => { |
yudao-admin-ui/src/views/login.vue
| @@ -45,7 +45,7 @@ | @@ -45,7 +45,7 @@ | ||
| 45 | </template> | 45 | </template> |
| 46 | 46 | ||
| 47 | <script> | 47 | <script> |
| 48 | -import { getCodeImg,thirdLoginRedirect } from "@/api/login"; | 48 | +import { getCodeImg,socialLoginRedirect } from "@/api/login"; |
| 49 | import Cookies from "js-cookie"; | 49 | import Cookies from "js-cookie"; |
| 50 | import { encrypt, decrypt } from '@/utils/jsencrypt' | 50 | import { encrypt, decrypt } from '@/utils/jsencrypt' |
| 51 | 51 | ||
| @@ -143,11 +143,11 @@ export default { | @@ -143,11 +143,11 @@ export default { | ||
| 143 | // 设置登陆中 | 143 | // 设置登陆中 |
| 144 | this.loading = true; | 144 | this.loading = true; |
| 145 | // 计算 redirectUri | 145 | // 计算 redirectUri |
| 146 | - // const redirectUri = location.origin + '/third-login'; | 146 | + const redirectUri = location.origin + '/social-login'; |
| 147 | // const redirectUri = 'http://127.0.0.1:48080/api/gitee/callback'; | 147 | // const redirectUri = 'http://127.0.0.1:48080/api/gitee/callback'; |
| 148 | - const redirectUri = 'http://127.0.0.1:48080/api/dingtalk/callback'; | 148 | + // const redirectUri = 'http://127.0.0.1:48080/api/dingtalk/callback'; |
| 149 | // 进行跳转 | 149 | // 进行跳转 |
| 150 | - thirdLoginRedirect(provider.type, redirectUri).then((res) => { | 150 | + socialLoginRedirect(provider.type, redirectUri).then((res) => { |
| 151 | // console.log(res.url); | 151 | // console.log(res.url); |
| 152 | window.location.href = res.data; | 152 | window.location.href = res.data; |
| 153 | }); | 153 | }); |
yudao-admin-ui/src/views/thirdLogin.vue renamed to yudao-admin-ui/src/views/socialLogin.vue
| @@ -28,7 +28,7 @@ | @@ -28,7 +28,7 @@ | ||
| 28 | </template> | 28 | </template> |
| 29 | 29 | ||
| 30 | <script> | 30 | <script> |
| 31 | -import { thirdLogin } from "@/api/login"; | 31 | +import { socialLogin } from "@/api/login"; |
| 32 | import Cookies from "js-cookie"; | 32 | import Cookies from "js-cookie"; |
| 33 | import { encrypt, decrypt } from '@/utils/jsencrypt' | 33 | import { encrypt, decrypt } from '@/utils/jsencrypt' |
| 34 | 34 | ||
| @@ -39,7 +39,7 @@ export default { | @@ -39,7 +39,7 @@ export default { | ||
| 39 | loginForm: { | 39 | loginForm: { |
| 40 | username: "admin", | 40 | username: "admin", |
| 41 | password: "admin123", | 41 | password: "admin123", |
| 42 | - rememberMe: false, | 42 | + rememberMe: false, // TODO 芋艿:后面看情况,去掉这块 |
| 43 | }, | 43 | }, |
| 44 | loginRules: { | 44 | loginRules: { |
| 45 | username: [ | 45 | username: [ |
| @@ -68,11 +68,17 @@ export default { | @@ -68,11 +68,17 @@ export default { | ||
| 68 | created() { | 68 | created() { |
| 69 | this.getCookie(); | 69 | this.getCookie(); |
| 70 | // 三方登陆相关 | 70 | // 三方登陆相关 |
| 71 | - this.type = 10; | 71 | + this.type = 20; |
| 72 | this.code = this.$route.query.code; | 72 | this.code = this.$route.query.code; |
| 73 | this.state = this.$route.query.state; | 73 | this.state = this.$route.query.state; |
| 74 | - thirdLogin(this.type, this.code, this.state).then(res => { | ||
| 75 | - debugger | 74 | + this.$store.dispatch("SocialLogin", { |
| 75 | + code: this.code, | ||
| 76 | + state: this.state, | ||
| 77 | + type: this.type | ||
| 78 | + }).then(() => { | ||
| 79 | + this.$router.push({ path: this.redirect || "/" }).catch(()=>{}); | ||
| 80 | + }).catch(() => { | ||
| 81 | + this.loading = false; | ||
| 76 | }); | 82 | }); |
| 77 | }, | 83 | }, |
| 78 | methods: { | 84 | methods: { |
| @@ -97,7 +103,13 @@ export default { | @@ -97,7 +103,13 @@ export default { | ||
| 97 | Cookies.remove("username"); | 103 | Cookies.remove("username"); |
| 98 | Cookies.remove("password"); | 104 | Cookies.remove("password"); |
| 99 | } | 105 | } |
| 100 | - this.$store.dispatch("Login", this.loginForm).then(() => { | 106 | + this.$store.dispatch("SocialLogin2", { |
| 107 | + code: this.code, | ||
| 108 | + state: this.state, | ||
| 109 | + type: this.type, | ||
| 110 | + username: this.loginForm.username, | ||
| 111 | + password: this.loginForm.password | ||
| 112 | + }).then(() => { | ||
| 101 | this.$router.push({ path: this.redirect || "/" }).catch(()=>{}); | 113 | this.$router.push({ path: this.redirect || "/" }).catch(()=>{}); |
| 102 | }).catch(() => { | 114 | }).catch(() => { |
| 103 | this.loading = false; | 115 | this.loading = false; |