forked from sfms3.0/sfms3.0
26 changed files with 2 additions and 926 deletions
@ -1,56 +0,0 @@ |
|||||
package com.win.module.system.api.social; |
|
||||
|
|
||||
import com.win.framework.common.exception.ServiceException; |
|
||||
import com.win.module.system.api.social.dto.SocialUserBindReqDTO; |
|
||||
import com.win.module.system.api.social.dto.SocialUserRespDTO; |
|
||||
import com.win.module.system.api.social.dto.SocialUserUnbindReqDTO; |
|
||||
import com.win.module.system.enums.social.SocialTypeEnum; |
|
||||
|
|
||||
import javax.validation.Valid; |
|
||||
|
|
||||
/** |
|
||||
* 社交用户的 API 接口 |
|
||||
* |
|
||||
* @author 闻荫源码 |
|
||||
*/ |
|
||||
public interface SocialUserApi { |
|
||||
|
|
||||
/** |
|
||||
* 获得社交平台的授权 URL |
|
||||
* |
|
||||
* @param type 社交平台的类型 {@link SocialTypeEnum} |
|
||||
* @param redirectUri 重定向 URL |
|
||||
* @return 社交平台的授权 URL |
|
||||
*/ |
|
||||
String getAuthorizeUrl(Integer type, String redirectUri); |
|
||||
|
|
||||
/** |
|
||||
* 绑定社交用户 |
|
||||
* |
|
||||
* @param reqDTO 绑定信息 |
|
||||
* @return 社交用户 openid |
|
||||
*/ |
|
||||
String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); |
|
||||
|
|
||||
/** |
|
||||
* 取消绑定社交用户 |
|
||||
* |
|
||||
* @param reqDTO 解绑 |
|
||||
*/ |
|
||||
void unbindSocialUser(@Valid SocialUserUnbindReqDTO reqDTO); |
|
||||
|
|
||||
/** |
|
||||
* 获得社交用户 |
|
||||
* |
|
||||
* 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 |
|
||||
* |
|
||||
* @param userType 用户类型 |
|
||||
* @param type 社交平台的类型 |
|
||||
* @param code 授权码 |
|
||||
* @param state state |
|
||||
* @return 社交用户 |
|
||||
*/ |
|
||||
SocialUserRespDTO getSocialUser(Integer userType, Integer type, |
|
||||
String code, String state); |
|
||||
|
|
||||
} |
|
@ -1,52 +0,0 @@ |
|||||
package com.win.module.system.api.social.dto; |
|
||||
|
|
||||
import com.win.framework.common.enums.UserTypeEnum; |
|
||||
import com.win.framework.common.validation.InEnum; |
|
||||
import com.win.module.system.enums.social.SocialTypeEnum; |
|
||||
import lombok.AllArgsConstructor; |
|
||||
import lombok.Data; |
|
||||
import lombok.NoArgsConstructor; |
|
||||
|
|
||||
import javax.validation.constraints.NotEmpty; |
|
||||
import javax.validation.constraints.NotNull; |
|
||||
|
|
||||
/** |
|
||||
* 取消绑定社交用户 Request DTO |
|
||||
* |
|
||||
* @author 闻荫源码 |
|
||||
*/ |
|
||||
@Data |
|
||||
@NoArgsConstructor |
|
||||
@AllArgsConstructor |
|
||||
public class SocialUserBindReqDTO { |
|
||||
|
|
||||
/** |
|
||||
* 用户编号 |
|
||||
*/ |
|
||||
@NotNull(message = "用户编号不能为空") |
|
||||
private Long userId; |
|
||||
/** |
|
||||
* 用户类型 |
|
||||
*/ |
|
||||
@InEnum(UserTypeEnum.class) |
|
||||
@NotNull(message = "用户类型不能为空") |
|
||||
private Integer userType; |
|
||||
|
|
||||
/** |
|
||||
* 社交平台的类型 |
|
||||
*/ |
|
||||
@InEnum(SocialTypeEnum.class) |
|
||||
@NotNull(message = "社交平台的类型不能为空") |
|
||||
private Integer type; |
|
||||
/** |
|
||||
* 授权码 |
|
||||
*/ |
|
||||
@NotEmpty(message = "授权码不能为空") |
|
||||
private String code; |
|
||||
/** |
|
||||
* state |
|
||||
*/ |
|
||||
@NotNull(message = "state 不能为空") |
|
||||
private String state; |
|
||||
|
|
||||
} |
|
@ -1,27 +0,0 @@ |
|||||
package com.win.module.system.api.social.dto; |
|
||||
|
|
||||
import lombok.AllArgsConstructor; |
|
||||
import lombok.Data; |
|
||||
import lombok.NoArgsConstructor; |
|
||||
|
|
||||
/** |
|
||||
* 社交用户 Response DTO |
|
||||
* |
|
||||
* @author 闻荫源码 |
|
||||
*/ |
|
||||
@Data |
|
||||
@NoArgsConstructor |
|
||||
@AllArgsConstructor |
|
||||
public class SocialUserRespDTO { |
|
||||
|
|
||||
/** |
|
||||
* 社交用户 openid |
|
||||
*/ |
|
||||
private String openid; |
|
||||
|
|
||||
/** |
|
||||
* 关联的用户编号 |
|
||||
*/ |
|
||||
private Long userId; |
|
||||
|
|
||||
} |
|
@ -1,44 +0,0 @@ |
|||||
package com.win.module.system.api.social.dto; |
|
||||
|
|
||||
import com.win.framework.common.enums.UserTypeEnum; |
|
||||
import com.win.framework.common.validation.InEnum; |
|
||||
import com.win.module.system.enums.social.SocialTypeEnum; |
|
||||
import lombok.Data; |
|
||||
|
|
||||
import javax.validation.constraints.NotEmpty; |
|
||||
import javax.validation.constraints.NotNull; |
|
||||
|
|
||||
/** |
|
||||
* 社交绑定 Request DTO,使用 code 授权码 |
|
||||
* |
|
||||
* @author 闻荫源码 |
|
||||
*/ |
|
||||
@Data |
|
||||
public class SocialUserUnbindReqDTO { |
|
||||
|
|
||||
/** |
|
||||
* 用户编号 |
|
||||
*/ |
|
||||
@NotNull(message = "用户编号不能为空") |
|
||||
private Long userId; |
|
||||
/** |
|
||||
* 用户类型 |
|
||||
*/ |
|
||||
@InEnum(UserTypeEnum.class) |
|
||||
@NotNull(message = "用户类型不能为空") |
|
||||
private Integer userType; |
|
||||
|
|
||||
/** |
|
||||
* 社交平台的类型 |
|
||||
*/ |
|
||||
@InEnum(SocialTypeEnum.class) |
|
||||
@NotNull(message = "社交平台的类型不能为空") |
|
||||
private Integer type; |
|
||||
|
|
||||
/** |
|
||||
* 社交平台的 unionId |
|
||||
*/ |
|
||||
@NotEmpty(message = "社交平台的 unionId 不能为空") |
|
||||
private String unionId; |
|
||||
|
|
||||
} |
|
@ -1,72 +0,0 @@ |
|||||
package com.win.module.system.enums.social; |
|
||||
|
|
||||
import cn.hutool.core.util.ArrayUtil; |
|
||||
import com.win.framework.common.core.IntArrayValuable; |
|
||||
import lombok.AllArgsConstructor; |
|
||||
import lombok.Getter; |
|
||||
|
|
||||
import java.util.Arrays; |
|
||||
|
|
||||
/** |
|
||||
* 社交平台的类型枚举 |
|
||||
* |
|
||||
* @author 闻荫源码 |
|
||||
*/ |
|
||||
@Getter |
|
||||
@AllArgsConstructor |
|
||||
public enum SocialTypeEnum implements IntArrayValuable { |
|
||||
|
|
||||
/** |
|
||||
* Gitee |
|
||||
* 文档链接:https://gitee.com/api/v5/oauth_doc#/
|
|
||||
*/ |
|
||||
GITEE(10, "GITEE"), |
|
||||
/** |
|
||||
* 钉钉 |
|
||||
* 文档链接:https://developers.dingtalk.com/document/app/obtain-identity-credentials
|
|
||||
*/ |
|
||||
DINGTALK(20, "DINGTALK"), |
|
||||
|
|
||||
/** |
|
||||
* 企业微信 |
|
||||
* 文档链接:https://xkcoding.com/2019/08/06/use-justauth-integration-wechat-enterprise.html
|
|
||||
*/ |
|
||||
WECHAT_ENTERPRISE(30, "WECHAT_ENTERPRISE"), |
|
||||
/** |
|
||||
* 微信公众平台 - 移动端 H5 |
|
||||
* 文档链接:https://www.cnblogs.com/juewuzhe/p/11905461.html
|
|
||||
*/ |
|
||||
WECHAT_MP(31, "WECHAT_MP"), |
|
||||
/** |
|
||||
* 微信开放平台 - 网站应用 PC 端扫码授权登录 |
|
||||
* 文档链接:https://justauth.wiki/guide/oauth/wechat_open/#_2-申请开发者资质认证
|
|
||||
*/ |
|
||||
WECHAT_OPEN(32, "WECHAT_OPEN"), |
|
||||
/** |
|
||||
* 微信小程序 |
|
||||
* 文档链接:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
|
|
||||
*/ |
|
||||
WECHAT_MINI_APP(34, "WECHAT_MINI_APP"), |
|
||||
; |
|
||||
|
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SocialTypeEnum::getType).toArray(); |
|
||||
|
|
||||
/** |
|
||||
* 类型 |
|
||||
*/ |
|
||||
private final Integer type; |
|
||||
/** |
|
||||
* 类型的标识 |
|
||||
*/ |
|
||||
private final String source; |
|
||||
|
|
||||
@Override |
|
||||
public int[] array() { |
|
||||
return ARRAYS; |
|
||||
} |
|
||||
|
|
||||
public static SocialTypeEnum valueOfType(Integer type) { |
|
||||
return ArrayUtil.firstMatch(o -> o.getType().equals(type), values()); |
|
||||
} |
|
||||
|
|
||||
} |
|
@ -1,45 +0,0 @@ |
|||||
package com.win.module.system.api.social; |
|
||||
|
|
||||
import com.win.module.system.api.social.dto.SocialUserBindReqDTO; |
|
||||
import com.win.module.system.api.social.dto.SocialUserRespDTO; |
|
||||
import com.win.module.system.api.social.dto.SocialUserUnbindReqDTO; |
|
||||
import com.win.module.system.service.social.SocialUserService; |
|
||||
import org.springframework.stereotype.Service; |
|
||||
import org.springframework.validation.annotation.Validated; |
|
||||
|
|
||||
import javax.annotation.Resource; |
|
||||
|
|
||||
/** |
|
||||
* 社交用户的 API 实现类 |
|
||||
* |
|
||||
* @author 闻荫源码 |
|
||||
*/ |
|
||||
@Service |
|
||||
@Validated |
|
||||
public class SocialUserApiImpl implements SocialUserApi { |
|
||||
|
|
||||
@Resource |
|
||||
private SocialUserService socialUserService; |
|
||||
|
|
||||
@Override |
|
||||
public String getAuthorizeUrl(Integer type, String redirectUri) { |
|
||||
return socialUserService.getAuthorizeUrl(type, redirectUri); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public String bindSocialUser(SocialUserBindReqDTO reqDTO) { |
|
||||
return socialUserService.bindSocialUser(reqDTO); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void unbindSocialUser(SocialUserUnbindReqDTO reqDTO) { |
|
||||
socialUserService.unbindSocialUser(reqDTO.getUserId(), reqDTO.getUserType(), |
|
||||
reqDTO.getType(), reqDTO.getUnionId()); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) { |
|
||||
return socialUserService.getSocialUser(userType, type, code, state); |
|
||||
} |
|
||||
|
|
||||
} |
|
@ -1,42 +0,0 @@ |
|||||
package com.win.module.system.controller.admin.socail; |
|
||||
|
|
||||
import com.win.framework.common.enums.UserTypeEnum; |
|
||||
import com.win.framework.common.pojo.CommonResult; |
|
||||
import com.win.module.system.controller.admin.socail.vo.SocialUserBindReqVO; |
|
||||
import com.win.module.system.controller.admin.socail.vo.SocialUserUnbindReqVO; |
|
||||
import com.win.module.system.convert.social.SocialUserConvert; |
|
||||
import com.win.module.system.service.social.SocialUserService; |
|
||||
import io.swagger.v3.oas.annotations.tags.Tag; |
|
||||
import io.swagger.v3.oas.annotations.Operation; |
|
||||
import org.springframework.validation.annotation.Validated; |
|
||||
import org.springframework.web.bind.annotation.*; |
|
||||
|
|
||||
import javax.annotation.Resource; |
|
||||
import javax.validation.Valid; |
|
||||
|
|
||||
import static com.win.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
|
||||
|
|
||||
@Tag(name = "管理后台 - 社交用户") |
|
||||
@RestController |
|
||||
@RequestMapping("/system/social-user") |
|
||||
@Validated |
|
||||
public class SocialUserController { |
|
||||
|
|
||||
@Resource |
|
||||
private SocialUserService socialUserService; |
|
||||
|
|
||||
@PostMapping("/bind") |
|
||||
@Operation(summary = "社交绑定,使用 code 授权码") |
|
||||
public CommonResult<Boolean> socialBind(@RequestBody @Valid SocialUserBindReqVO reqVO) { |
|
||||
socialUserService.bindSocialUser(SocialUserConvert.INSTANCE.convert(getLoginUserId(), UserTypeEnum.ADMIN.getValue(), reqVO)); |
|
||||
return CommonResult.success(true); |
|
||||
} |
|
||||
|
|
||||
@DeleteMapping("/unbind") |
|
||||
@Operation(summary = "取消社交绑定") |
|
||||
public CommonResult<Boolean> socialUnbind(@RequestBody SocialUserUnbindReqVO reqVO) { |
|
||||
socialUserService.unbindSocialUser(getLoginUserId(), UserTypeEnum.ADMIN.getValue(), reqVO.getType(), reqVO.getOpenid()); |
|
||||
return CommonResult.success(true); |
|
||||
} |
|
||||
|
|
||||
} |
|
@ -1,34 +0,0 @@ |
|||||
package com.win.module.system.controller.admin.socail.vo; |
|
||||
|
|
||||
import com.win.module.system.enums.social.SocialTypeEnum; |
|
||||
import com.win.framework.common.validation.InEnum; |
|
||||
import io.swagger.v3.oas.annotations.media.Schema; |
|
||||
import lombok.AllArgsConstructor; |
|
||||
import lombok.Builder; |
|
||||
import lombok.Data; |
|
||||
import lombok.NoArgsConstructor; |
|
||||
|
|
||||
import javax.validation.constraints.NotEmpty; |
|
||||
import javax.validation.constraints.NotNull; |
|
||||
|
|
||||
@Schema(description = "管理后台 - 社交绑定 Request VO,使用 code 授权码") |
|
||||
@Data |
|
||||
@NoArgsConstructor |
|
||||
@AllArgsConstructor |
|
||||
@Builder |
|
||||
public class SocialUserBindReqVO { |
|
||||
|
|
||||
@Schema(description = "社交平台的类型,参见 UserSocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") |
|
||||
@InEnum(SocialTypeEnum.class) |
|
||||
@NotNull(message = "社交平台的类型不能为空") |
|
||||
private Integer type; |
|
||||
|
|
||||
@Schema(description = "授权码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
|
||||
@NotEmpty(message = "授权码不能为空") |
|
||||
private String code; |
|
||||
|
|
||||
@Schema(description = "state", requiredMode = Schema.RequiredMode.REQUIRED, example = "9b2ffbc1-7425-4155-9894-9d5c08541d62") |
|
||||
@NotEmpty(message = "state 不能为空") |
|
||||
private String state; |
|
||||
|
|
||||
} |
|
@ -1,30 +0,0 @@ |
|||||
package com.win.module.system.controller.admin.socail.vo; |
|
||||
|
|
||||
import com.win.framework.common.validation.InEnum; |
|
||||
import com.win.module.system.enums.social.SocialTypeEnum; |
|
||||
import io.swagger.v3.oas.annotations.media.Schema; |
|
||||
import lombok.AllArgsConstructor; |
|
||||
import lombok.Builder; |
|
||||
import lombok.Data; |
|
||||
import lombok.NoArgsConstructor; |
|
||||
|
|
||||
import javax.validation.constraints.NotEmpty; |
|
||||
import javax.validation.constraints.NotNull; |
|
||||
|
|
||||
@Schema(description = "管理后台 - 取消社交绑定 Request VO") |
|
||||
@Data |
|
||||
@NoArgsConstructor |
|
||||
@AllArgsConstructor |
|
||||
@Builder |
|
||||
public class SocialUserUnbindReqVO { |
|
||||
|
|
||||
@Schema(description = "社交平台的类型,参见 UserSocialTypeEnum 枚举值", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") |
|
||||
@InEnum(SocialTypeEnum.class) |
|
||||
@NotNull(message = "社交平台的类型不能为空") |
|
||||
private Integer type; |
|
||||
|
|
||||
@Schema(description = "社交用户的 openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "IPRmJ0wvBptiPIlGEZiPewGwiEiE") |
|
||||
@NotEmpty(message = "社交用户的 openid 不能为空") |
|
||||
private String openid; |
|
||||
|
|
||||
} |
|
@ -1,19 +0,0 @@ |
|||||
package com.win.module.system.convert.social; |
|
||||
|
|
||||
import com.win.module.system.api.social.dto.SocialUserBindReqDTO; |
|
||||
import com.win.module.system.api.social.dto.SocialUserUnbindReqDTO; |
|
||||
import com.win.module.system.controller.admin.socail.vo.SocialUserBindReqVO; |
|
||||
import com.win.module.system.controller.admin.socail.vo.SocialUserUnbindReqVO; |
|
||||
import org.mapstruct.Mapper; |
|
||||
import org.mapstruct.factory.Mappers; |
|
||||
|
|
||||
@Mapper |
|
||||
public interface SocialUserConvert { |
|
||||
|
|
||||
SocialUserConvert INSTANCE = Mappers.getMapper(SocialUserConvert.class); |
|
||||
|
|
||||
SocialUserBindReqDTO convert(Long userId, Integer userType, SocialUserBindReqVO reqVO); |
|
||||
|
|
||||
SocialUserUnbindReqDTO convert(Long userId, Integer userType, SocialUserUnbindReqVO reqVO); |
|
||||
|
|
||||
} |
|
@ -1,56 +0,0 @@ |
|||||
package com.win.module.system.dal.dataobject.social; |
|
||||
|
|
||||
import com.win.framework.common.enums.UserTypeEnum; |
|
||||
import com.win.framework.mybatis.core.dataobject.BaseDO; |
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence; |
|
||||
import com.baomidou.mybatisplus.annotation.TableId; |
|
||||
import com.baomidou.mybatisplus.annotation.TableName; |
|
||||
import lombok.*; |
|
||||
|
|
||||
/** |
|
||||
* 社交用户的绑定 |
|
||||
* 即 {@link SocialUserDO} 与 UserDO 的关联表 |
|
||||
* |
|
||||
* @author 闻荫源码 |
|
||||
*/ |
|
||||
@TableName(value = "system_social_user_bind", autoResultMap = true) |
|
||||
@KeySequence("system_social_user_bind_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
|
||||
@Data |
|
||||
@EqualsAndHashCode(callSuper = true) |
|
||||
@Builder |
|
||||
@NoArgsConstructor |
|
||||
@AllArgsConstructor |
|
||||
public class SocialUserBindDO extends BaseDO { |
|
||||
|
|
||||
/** |
|
||||
* 编号 |
|
||||
*/ |
|
||||
@TableId |
|
||||
private Long id; |
|
||||
/** |
|
||||
* 关联的用户编号 |
|
||||
* |
|
||||
* 关联 UserDO 的编号 |
|
||||
*/ |
|
||||
private Long userId; |
|
||||
/** |
|
||||
* 用户类型 |
|
||||
* |
|
||||
* 枚举 {@link UserTypeEnum} |
|
||||
*/ |
|
||||
private Integer userType; |
|
||||
|
|
||||
/** |
|
||||
* 社交平台的用户编号 |
|
||||
* |
|
||||
* 关联 {@link SocialUserDO#getId()} |
|
||||
*/ |
|
||||
private Long socialUserId; |
|
||||
/** |
|
||||
* 社交平台的类型 |
|
||||
* |
|
||||
* 冗余 {@link SocialUserDO#getType()} |
|
||||
*/ |
|
||||
private Integer socialType; |
|
||||
|
|
||||
} |
|
@ -1,73 +0,0 @@ |
|||||
package com.win.module.system.dal.dataobject.social; |
|
||||
|
|
||||
import com.win.framework.mybatis.core.dataobject.BaseDO; |
|
||||
import com.win.module.system.enums.social.SocialTypeEnum; |
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence; |
|
||||
import com.baomidou.mybatisplus.annotation.TableId; |
|
||||
import com.baomidou.mybatisplus.annotation.TableName; |
|
||||
import lombok.*; |
|
||||
|
|
||||
/** |
|
||||
* 社交(三方)用户 |
|
||||
* |
|
||||
* @author weir |
|
||||
*/ |
|
||||
@TableName(value = "system_social_user", autoResultMap = true) |
|
||||
@KeySequence("system_social_user_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
|
||||
@Data |
|
||||
@EqualsAndHashCode(callSuper = true) |
|
||||
@Builder |
|
||||
@NoArgsConstructor |
|
||||
@AllArgsConstructor |
|
||||
public class SocialUserDO extends BaseDO { |
|
||||
|
|
||||
/** |
|
||||
* 自增主键 |
|
||||
*/ |
|
||||
@TableId |
|
||||
private Long id; |
|
||||
/** |
|
||||
* 社交平台的类型 |
|
||||
* |
|
||||
* 枚举 {@link SocialTypeEnum} |
|
||||
*/ |
|
||||
private Integer type; |
|
||||
|
|
||||
/** |
|
||||
* 社交 openid |
|
||||
*/ |
|
||||
private String openid; |
|
||||
/** |
|
||||
* 社交 token |
|
||||
*/ |
|
||||
private String token; |
|
||||
/** |
|
||||
* 原始 Token 数据,一般是 JSON 格式 |
|
||||
*/ |
|
||||
private String rawTokenInfo; |
|
||||
|
|
||||
/** |
|
||||
* 用户昵称 |
|
||||
*/ |
|
||||
private String nickname; |
|
||||
/** |
|
||||
* 用户头像 |
|
||||
*/ |
|
||||
private String avatar; |
|
||||
/** |
|
||||
* 原始用户数据,一般是 JSON 格式 |
|
||||
*/ |
|
||||
private String rawUserInfo; |
|
||||
|
|
||||
/** |
|
||||
* 最后一次的认证 code |
|
||||
*/ |
|
||||
private String code; |
|
||||
/** |
|
||||
* 最后一次的认证 state |
|
||||
*/ |
|
||||
private String state; |
|
||||
|
|
||||
} |
|
||||
|
|
||||
|
|
@ -1,37 +0,0 @@ |
|||||
package com.win.module.system.dal.mysql.social; |
|
||||
|
|
||||
import com.win.framework.mybatis.core.mapper.BaseMapperX; |
|
||||
import com.win.framework.mybatis.core.query.LambdaQueryWrapperX; |
|
||||
import com.win.module.system.dal.dataobject.social.SocialUserBindDO; |
|
||||
import org.apache.ibatis.annotations.Mapper; |
|
||||
|
|
||||
import java.util.List; |
|
||||
|
|
||||
@Mapper |
|
||||
public interface SocialUserBindMapper extends BaseMapperX<SocialUserBindDO> { |
|
||||
|
|
||||
default void deleteByUserTypeAndUserIdAndSocialType(Integer userType, Long userId, Integer socialType) { |
|
||||
delete(new LambdaQueryWrapperX<SocialUserBindDO>() |
|
||||
.eq(SocialUserBindDO::getUserType, userType) |
|
||||
.eq(SocialUserBindDO::getUserId, userId) |
|
||||
.eq(SocialUserBindDO::getSocialType, socialType)); |
|
||||
} |
|
||||
|
|
||||
default void deleteByUserTypeAndSocialUserId(Integer userType, Long socialUserId) { |
|
||||
delete(new LambdaQueryWrapperX<SocialUserBindDO>() |
|
||||
.eq(SocialUserBindDO::getUserType, userType) |
|
||||
.eq(SocialUserBindDO::getSocialUserId, socialUserId)); |
|
||||
} |
|
||||
|
|
||||
default SocialUserBindDO selectByUserTypeAndSocialUserId(Integer userType, Long socialUserId) { |
|
||||
return selectOne(SocialUserBindDO::getUserType, userType, |
|
||||
SocialUserBindDO::getSocialUserId, socialUserId); |
|
||||
} |
|
||||
|
|
||||
default List<SocialUserBindDO> selectListByUserIdAndUserType(Long userId, Integer userType) { |
|
||||
return selectList(new LambdaQueryWrapperX<SocialUserBindDO>() |
|
||||
.eq(SocialUserBindDO::getUserId, userId) |
|
||||
.eq(SocialUserBindDO::getUserType, userType)); |
|
||||
} |
|
||||
|
|
||||
} |
|
@ -1,28 +0,0 @@ |
|||||
package com.win.module.system.dal.mysql.social; |
|
||||
|
|
||||
import com.win.module.system.dal.dataobject.social.SocialUserDO; |
|
||||
import com.win.framework.mybatis.core.mapper.BaseMapperX; |
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
|
||||
import org.apache.ibatis.annotations.Mapper; |
|
||||
|
|
||||
import java.util.Collection; |
|
||||
import java.util.List; |
|
||||
|
|
||||
@Mapper |
|
||||
public interface SocialUserMapper extends BaseMapperX<SocialUserDO> { |
|
||||
|
|
||||
default SocialUserDO selectByTypeAndCodeAnState(Integer type, String code, String state) { |
|
||||
return selectOne(new LambdaQueryWrapper<SocialUserDO>() |
|
||||
.eq(SocialUserDO::getType, type) |
|
||||
.eq(SocialUserDO::getCode, code) |
|
||||
.eq(SocialUserDO::getState, state)); |
|
||||
} |
|
||||
|
|
||||
default SocialUserDO selectByTypeAndOpenid(Integer type, String openid) { |
|
||||
return selectOne(new LambdaQueryWrapper<SocialUserDO>() |
|
||||
.eq(SocialUserDO::getType, type) |
|
||||
.eq(SocialUserDO::getOpenid, openid)); |
|
||||
} |
|
||||
|
|
||||
} |
|
@ -1,81 +0,0 @@ |
|||||
package com.win.module.system.service.social; |
|
||||
|
|
||||
import com.win.framework.common.exception.ServiceException; |
|
||||
import com.win.module.system.api.social.dto.SocialUserBindReqDTO; |
|
||||
import com.win.module.system.api.social.dto.SocialUserRespDTO; |
|
||||
import com.win.module.system.dal.dataobject.social.SocialUserDO; |
|
||||
import com.win.module.system.enums.social.SocialTypeEnum; |
|
||||
|
|
||||
import javax.validation.Valid; |
|
||||
import javax.validation.constraints.NotNull; |
|
||||
import java.util.List; |
|
||||
|
|
||||
/** |
|
||||
* 社交用户 Service 接口,例如说社交平台的授权登录 |
|
||||
* |
|
||||
* @author 闻荫源码 |
|
||||
*/ |
|
||||
public interface SocialUserService { |
|
||||
|
|
||||
/** |
|
||||
* 获得社交平台的授权 URL |
|
||||
* |
|
||||
* @param type 社交平台的类型 {@link SocialTypeEnum} |
|
||||
* @param redirectUri 重定向 URL |
|
||||
* @return 社交平台的授权 URL |
|
||||
*/ |
|
||||
String getAuthorizeUrl(Integer type, String redirectUri); |
|
||||
|
|
||||
/** |
|
||||
* 授权获得对应的社交用户 |
|
||||
* 如果授权失败,则会抛出 {@link ServiceException} 异常 |
|
||||
* |
|
||||
* @param type 社交平台的类型 {@link SocialTypeEnum} |
|
||||
* @param code 授权码 |
|
||||
* @param state state |
|
||||
* @return 授权用户 |
|
||||
*/ |
|
||||
@NotNull |
|
||||
SocialUserDO authSocialUser(Integer type, String code, String state); |
|
||||
|
|
||||
/** |
|
||||
* 获得指定用户的社交用户列表 |
|
||||
* |
|
||||
* @param userId 用户编号 |
|
||||
* @param userType 用户类型 |
|
||||
* @return 社交用户列表 |
|
||||
*/ |
|
||||
List<SocialUserDO> getSocialUserList(Long userId, Integer userType); |
|
||||
|
|
||||
/** |
|
||||
* 绑定社交用户 |
|
||||
* |
|
||||
* @param reqDTO 绑定信息 |
|
||||
* @return 社交用户 openid |
|
||||
*/ |
|
||||
String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO); |
|
||||
|
|
||||
/** |
|
||||
* 取消绑定社交用户 |
|
||||
* |
|
||||
* @param userId 用户编号 |
|
||||
* @param userType 全局用户类型 |
|
||||
* @param type 社交平台的类型 {@link SocialTypeEnum} |
|
||||
* @param openid 社交平台的 openid |
|
||||
*/ |
|
||||
void unbindSocialUser(Long userId, Integer userType, Integer type, String openid); |
|
||||
|
|
||||
/** |
|
||||
* 获得社交用户 |
|
||||
* |
|
||||
* 在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常 |
|
||||
* |
|
||||
* @param userType 用户类型 |
|
||||
* @param type 社交平台的类型 |
|
||||
* @param code 授权码 |
|
||||
* @param state state |
|
||||
* @return 社交用户 |
|
||||
*/ |
|
||||
SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state); |
|
||||
|
|
||||
} |
|
@ -1,169 +0,0 @@ |
|||||
package com.win.module.system.service.social; |
|
||||
|
|
||||
import cn.hutool.core.collection.CollUtil; |
|
||||
import cn.hutool.core.lang.Assert; |
|
||||
import com.win.framework.common.util.http.HttpUtils; |
|
||||
import com.win.framework.social.core.WinAuthRequestFactory; |
|
||||
import com.win.module.system.api.social.dto.SocialUserBindReqDTO; |
|
||||
import com.win.module.system.api.social.dto.SocialUserRespDTO; |
|
||||
import com.win.module.system.dal.dataobject.social.SocialUserBindDO; |
|
||||
import com.win.module.system.dal.dataobject.social.SocialUserDO; |
|
||||
import com.win.module.system.dal.mysql.social.SocialUserBindMapper; |
|
||||
import com.win.module.system.dal.mysql.social.SocialUserMapper; |
|
||||
import com.win.module.system.enums.social.SocialTypeEnum; |
|
||||
import com.xingyuv.jushauth.model.AuthCallback; |
|
||||
import com.xingyuv.jushauth.model.AuthResponse; |
|
||||
import com.xingyuv.jushauth.model.AuthUser; |
|
||||
import com.xingyuv.jushauth.request.AuthRequest; |
|
||||
import com.xingyuv.jushauth.utils.AuthStateUtils; |
|
||||
import lombok.extern.slf4j.Slf4j; |
|
||||
import org.springframework.stereotype.Service; |
|
||||
import org.springframework.transaction.annotation.Transactional; |
|
||||
import org.springframework.validation.annotation.Validated; |
|
||||
|
|
||||
import javax.annotation.Resource; |
|
||||
import java.util.Collections; |
|
||||
import java.util.List; |
|
||||
|
|
||||
import static com.win.framework.common.exception.util.ServiceExceptionUtil.exception; |
|
||||
import static com.win.framework.common.util.collection.CollectionUtils.convertSet; |
|
||||
import static com.win.framework.common.util.json.JsonUtils.toJsonString; |
|
||||
import static com.win.module.system.enums.ErrorCodeConstants.*; |
|
||||
|
|
||||
/** |
|
||||
* 社交用户 Service 实现类 |
|
||||
* |
|
||||
* @author 闻荫源码 |
|
||||
*/ |
|
||||
@Service |
|
||||
@Validated |
|
||||
@Slf4j |
|
||||
public class SocialUserServiceImpl implements SocialUserService { |
|
||||
|
|
||||
@Resource// 由于自定义了 WinAuthRequestFactory 无法覆盖默认的 AuthRequestFactory,所以只能注入它
|
|
||||
private WinAuthRequestFactory winAuthRequestFactory; |
|
||||
|
|
||||
@Resource |
|
||||
private SocialUserBindMapper socialUserBindMapper; |
|
||||
@Resource |
|
||||
private SocialUserMapper socialUserMapper; |
|
||||
|
|
||||
@Override |
|
||||
public String getAuthorizeUrl(Integer type, String redirectUri) { |
|
||||
// 获得对应的 AuthRequest 实现
|
|
||||
AuthRequest authRequest = winAuthRequestFactory.get(SocialTypeEnum.valueOfType(type).getSource()); |
|
||||
// 生成跳转地址
|
|
||||
String authorizeUri = authRequest.authorize(AuthStateUtils.createState()); |
|
||||
return HttpUtils.replaceUrlQuery(authorizeUri, "redirect_uri", redirectUri); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SocialUserDO authSocialUser(Integer type, String code, String state) { |
|
||||
// 优先从 DB 中获取,因为 code 有且可以使用一次。
|
|
||||
// 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次
|
|
||||
SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(type, code, state); |
|
||||
if (socialUser != null) { |
|
||||
return socialUser; |
|
||||
} |
|
||||
|
|
||||
// 请求获取
|
|
||||
AuthUser authUser = getAuthUser(type, code, state); |
|
||||
Assert.notNull(authUser, "三方用户不能为空"); |
|
||||
|
|
||||
// 保存到 DB 中
|
|
||||
socialUser = socialUserMapper.selectByTypeAndOpenid(type, authUser.getUuid()); |
|
||||
if (socialUser == null) { |
|
||||
socialUser = new SocialUserDO(); |
|
||||
} |
|
||||
socialUser.setType(type).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询
|
|
||||
.setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken()))) |
|
||||
.setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo())); |
|
||||
if (socialUser.getId() == null) { |
|
||||
socialUserMapper.insert(socialUser); |
|
||||
} else { |
|
||||
socialUserMapper.updateById(socialUser); |
|
||||
} |
|
||||
return socialUser; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public List<SocialUserDO> getSocialUserList(Long userId, Integer userType) { |
|
||||
// 获得绑定
|
|
||||
List<SocialUserBindDO> socialUserBinds = socialUserBindMapper.selectListByUserIdAndUserType(userId, userType); |
|
||||
if (CollUtil.isEmpty(socialUserBinds)) { |
|
||||
return Collections.emptyList(); |
|
||||
} |
|
||||
// 获得社交用户
|
|
||||
return socialUserMapper.selectBatchIds(convertSet(socialUserBinds, SocialUserBindDO::getSocialUserId)); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
@Transactional |
|
||||
public String bindSocialUser(SocialUserBindReqDTO reqDTO) { |
|
||||
// 获得社交用户
|
|
||||
SocialUserDO socialUser = authSocialUser(reqDTO.getType(), reqDTO.getCode(), reqDTO.getState()); |
|
||||
Assert.notNull(socialUser, "社交用户不能为空"); |
|
||||
|
|
||||
// 社交用户可能之前绑定过别的用户,需要进行解绑
|
|
||||
socialUserBindMapper.deleteByUserTypeAndSocialUserId(reqDTO.getUserType(), socialUser.getId()); |
|
||||
|
|
||||
// 用户可能之前已经绑定过该社交类型,需要进行解绑
|
|
||||
socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(reqDTO.getUserType(), reqDTO.getUserId(), |
|
||||
socialUser.getType()); |
|
||||
|
|
||||
// 绑定当前登录的社交用户
|
|
||||
SocialUserBindDO socialUserBind = SocialUserBindDO.builder() |
|
||||
.userId(reqDTO.getUserId()).userType(reqDTO.getUserType()) |
|
||||
.socialUserId(socialUser.getId()).socialType(socialUser.getType()).build(); |
|
||||
socialUserBindMapper.insert(socialUserBind); |
|
||||
return socialUser.getOpenid(); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void unbindSocialUser(Long userId, Integer userType, Integer type, String openid) { |
|
||||
// 获得 openid 对应的 SocialUserDO 社交用户
|
|
||||
SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(type, openid); |
|
||||
if (socialUser == null) { |
|
||||
throw exception(SOCIAL_USER_NOT_FOUND); |
|
||||
} |
|
||||
|
|
||||
// 获得对应的社交绑定关系
|
|
||||
socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(userType, userId, socialUser.getType()); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public SocialUserRespDTO getSocialUser(Integer userType, Integer type, String code, String state) { |
|
||||
// 获得社交用户
|
|
||||
SocialUserDO socialUser = authSocialUser(type, code, state); |
|
||||
Assert.notNull(socialUser, "社交用户不能为空"); |
|
||||
|
|
||||
// 如果未绑定的社交用户,则无法自动登录,进行报错
|
|
||||
SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType, |
|
||||
socialUser.getId()); |
|
||||
if (socialUserBind == null) { |
|
||||
throw exception(AUTH_THIRD_LOGIN_NOT_BIND); |
|
||||
} |
|
||||
return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId()); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 请求社交平台,获得授权的用户 |
|
||||
* |
|
||||
* @param type 社交平台的类型 |
|
||||
* @param code 授权码 |
|
||||
* @param state 授权 state |
|
||||
* @return 授权的用户 |
|
||||
*/ |
|
||||
private AuthUser getAuthUser(Integer type, String code, String state) { |
|
||||
AuthRequest authRequest = winAuthRequestFactory.get(SocialTypeEnum.valueOfType(type).getSource()); |
|
||||
AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build(); |
|
||||
AuthResponse<?> authResponse = authRequest.login(authCallback); |
|
||||
log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", type, |
|
||||
toJsonString(authCallback), toJsonString(authResponse)); |
|
||||
if (!authResponse.ok()) { |
|
||||
throw exception(SOCIAL_USER_AUTH_FAILURE, authResponse.getMsg()); |
|
||||
} |
|
||||
return (AuthUser) authResponse.getData(); |
|
||||
} |
|
||||
|
|
||||
} |
|
Loading…
Reference in new issue