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