Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/activiti

 Conflicts:
	sql/ruoyi-vue-pro.sql
	yudao-admin-server/src/main/resources/application.yaml
	yudao-admin-server/src/main/resources/mybatis-config/mybatis-config.xml
	yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
	yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java
This commit is contained in:
YunaiV
2021-12-30 19:58:31 +08:00
700 changed files with 58868 additions and 1158 deletions

View File

@@ -36,6 +36,14 @@
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-pay</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-social</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
@@ -91,17 +99,12 @@
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- 三方云服务相关 -->
<dependency>
<groupId>com.xkcoding.justauth</groupId>
<artifactId>justauth-spring-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,6 +1,7 @@
package cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
@@ -21,7 +22,7 @@ import java.io.InputStream;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class InfFileDO extends BaseDO {
public class InfFileDO extends TenantBaseDO {
/**
* 文件路径

View File

@@ -2,7 +2,7 @@ package cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@@ -21,7 +21,7 @@ import java.util.Date;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class InfApiAccessLogDO extends BaseDO {
public class InfApiAccessLogDO extends TenantBaseDO {
/**
* 编号

View File

@@ -1,8 +1,8 @@
package cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.coreservice.modules.infra.enums.logger.InfApiErrorLogProcessStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@@ -21,7 +21,7 @@ import java.util.Date;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class InfApiErrorLogDO extends BaseDO {
public class InfApiErrorLogDO extends TenantBaseDO {
/**
* 编号

View File

@@ -2,11 +2,27 @@ package cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.file;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface InfFileCoreMapper extends BaseMapperX<InfFileDO> {
default Integer selectCountById(String id) {
return selectCount("id", id);
}
/**
* 基于 Path 获取文件
* 实际上,是基于 ID 查询
* 由于前端使用 <img /> 的方式获取图片,所以需要忽略租户的查询
*
* @param path 路径
* @return 文件
*/
@InterceptorIgnore(tenantLine = "true")
default InfFileDO selectByPath(String path) {
return selectById(path);
}
}

View File

@@ -58,7 +58,7 @@ public class InfFileCoreServiceImpl implements InfFileCoreService {
@Override
public InfFileDO getFile(String path) {
return fileMapper.selectById(path);
return fileMapper.selectByPath(path);
}
}

View File

@@ -1,7 +1,7 @@
package cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@@ -22,7 +22,7 @@ import java.util.Date;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MbrUserDO extends BaseDO {
public class MbrUserDO extends TenantBaseDO {
/**
* 用户ID

View File

@@ -1,33 +0,0 @@
package cn.iocoder.yudao.coreservice.modules.system.compent.justauth;
import me.zhyd.oauth.config.AuthSource;
public enum AuthExtendSource implements AuthSource {
/**
* 微信小程序授权登录
*/
WECHAT_MINI_PROGRAM{
@Override
public String authorize() {
// https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
throw new UnsupportedOperationException("不支持获取授权url, 请使用小程序内置函数wx.login()登录获取code");
}
@Override
public String accessToken() {
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
// 获取openid, unionid , session_key
return "https://api.weixin.qq.com/sns/jscode2session";
}
@Override
public String userInfo() {
//https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html
throw new UnsupportedOperationException("不支持获取用户信息url, 请使用小程序内置函数wx.getUserProfile()获取用户信息");
}
}
;
}

View File

@@ -1,22 +0,0 @@
package cn.iocoder.yudao.coreservice.modules.system.compent.justauth;
import lombok.*;
import me.zhyd.oauth.model.AuthToken;
/**
* TODO @timfruit类注释
* @author timfruit
* @date 2021-10-29
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class AuthExtendToken extends AuthToken {
/**
* 微信小程序 会话密钥
*/
private String miniSessionKey;
}

View File

@@ -1,90 +0,0 @@
package cn.iocoder.yudao.coreservice.modules.system.compent.justauth;
import com.alibaba.fastjson.JSONObject;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthDefaultRequest;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.UrlBuilder;
// TODO @timfruit新建一个 yudao-spring-boot-starter-biz-social 包,把这个拓展拿进去哈。另外,可以思考下。
// 1. application-local.yaml 的配置里justauth.extend.enum-class 能否不配置,而是自动配置好
// 2. application-local.yaml 的配置里justauth.extend.extend.config.WECHAT_MINI_PROGRAM 有办法和 justauth.type.WECHAT_MP 持平
/**
* 微信小程序登陆
*
* @author timfruit
* @date 2021-10-29
*/
public class AuthWeChatMiniProgramRequest extends AuthDefaultRequest {
public AuthWeChatMiniProgramRequest(AuthConfig config) {
super(config, AuthExtendSource.WECHAT_MINI_PROGRAM);
}
public AuthWeChatMiniProgramRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthExtendSource.WECHAT_MINI_PROGRAM, authStateCache);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
// https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
String response = new HttpUtils(config.getHttpConfig()).get(accessTokenUrl(authCallback.getCode()));
JSONObject accessTokenObject = JSONObject.parseObject(response); // TODO @timfruit使用 JsonUtils项目尽量避免直接使用某个 json 库
this.checkResponse(accessTokenObject);
AuthExtendToken token = new AuthExtendToken();
token.setMiniSessionKey(accessTokenObject.getString("session_key"));
token.setOpenId(accessTokenObject.getString("openid"));
token.setUnionId(accessTokenObject.getString("unionid"));
return token;
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
// https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html
// 如果需要用户信息,需要在小程序调用函数后传给后端
return AuthUser.builder()
.uuid(authToken.getOpenId())
//TODO 是使用默认值,还是有小程序获取用户信息 和 code 一起传过来
.nickname("")
.avatar("")
.token(authToken)
.source(source.toString())
.build();
}
/**
* 检查响应内容是否正确
*
* @param object 请求响应内容
*/
private void checkResponse(JSONObject object) {
int code = object.getIntValue("errcode");
if(code != 0){ // TODO @timfruitif (code != 0) { ,注意空格
throw new AuthException(object.getIntValue("errcode"), object.getString("errmsg"));
}
}
/**
* 返回获取 accessToken 的 url
*
* @param code 授权码
* @return 返回获取 accessToken 的 url
*/
@Override
protected String accessTokenUrl(String code) {
return UrlBuilder.fromBaseUrl(source.accessToken())
.queryParam("appid", config.getClientId())
.queryParam("secret", config.getClientSecret())
.queryParam("js_code", code)
.queryParam("grant_type", "authorization_code")
.build();
}
}

View File

@@ -1,8 +1,8 @@
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -25,7 +25,7 @@ import java.util.Date;
@Data
@Builder
@EqualsAndHashCode(callSuper = true)
public class SysUserSessionDO extends BaseDO {
public class SysUserSessionDO extends TenantBaseDO {
/**
* 会话编号, 即 sessionId

View File

@@ -0,0 +1,45 @@
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
* 租户 DO
*
* @author 芋道源码
*/
@TableName(value = "sys_tenant", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SysTenantDO extends BaseDO {
/**
* 租户编号,自增
*/
private Long id;
/**
* 租户名,唯一
*/
private String name;
/**
* 联系人
*/
private String contactName;
/**
* 联系手机
*/
private String contactMobile;
/**
* 帐号状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
}

View File

@@ -2,8 +2,8 @@ package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user;
import cn.iocoder.yudao.coreservice.modules.system.enums.common.SysSexEnum;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -24,7 +24,7 @@ import java.util.Set;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SysUserDO extends BaseDO {
public class SysUserDO extends TenantBaseDO {
/**
* 用户ID

View File

@@ -8,9 +8,8 @@ import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
// TODO @timfruitSysSocialUserCoreMapper 改名方便区分
@Mapper
public interface SysSocialUserMapper extends BaseMapperX<SysSocialUserDO> {
public interface SysSocialUserCoreMapper extends BaseMapperX<SysSocialUserDO> {
default List<SysSocialUserDO> selectListByTypeAndUnionId(Integer userType, Collection<Integer> types, String unionId) {
return selectList(new QueryWrapper<SysSocialUserDO>().eq("user_type", userType)

View File

@@ -0,0 +1,9 @@
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.tenant;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysTenantCoreMapper extends BaseMapperX<SysTenantDO> {
}

View File

@@ -10,9 +10,8 @@ import javax.annotation.Resource;
import static cn.iocoder.yudao.coreservice.modules.system.dal.redis.SysRedisKeyCoreConstants.SOCIAL_AUTH_USER;
// TODO @timfruit这里的 AuthUser 还是保留全路径,主要想体现出来,不是自己定义的
/**
* 社交 {@link AuthUser} 的 RedisDAO
* 社交 {@link me.zhyd.oauth.model.AuthUser} 的 RedisDAO
*
* @author 芋道源码
*/

View File

@@ -1,8 +1,9 @@
package cn.iocoder.yudao.coreservice.modules.system.mq.message.sms;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.mq.core.stream.StreamMessage;
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
import java.util.List;
@@ -13,7 +14,8 @@ import java.util.List;
* @author 芋道源码
*/
@Data
public class SysSmsSendMessage implements StreamMessage {
@EqualsAndHashCode(callSuper = true)
public class SysSmsSendMessage extends AbstractStreamMessage {
/**
* 短信日志编号

View File

@@ -2,9 +2,8 @@ package cn.iocoder.yudao.coreservice.modules.system.mq.producer.sms;
import cn.iocoder.yudao.coreservice.modules.system.mq.message.sms.SysSmsSendMessage;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@@ -21,7 +20,7 @@ import java.util.List;
public class SysSmsCoreProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysSmsSendMessage} 消息
@@ -36,7 +35,7 @@ public class SysSmsCoreProducer {
Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
SysSmsSendMessage message = new SysSmsSendMessage().setLogId(logId).setMobile(mobile);
message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams);
RedisMessageUtils.sendStreamMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@@ -15,8 +15,7 @@ import java.util.List;
*
* @author 芋道源码
*/
// TODO @timfruitSysSocialCoreService 改名方便区分
public interface SysSocialService {
public interface SysSocialCoreService {
/**
* 获得社交平台的授权 URL
@@ -50,6 +49,7 @@ public interface SysSocialService {
* @param type 社交平台的类型 {@link SysSocialTypeEnum}
* @param unionId 社交平台的 unionId
* @return 社交用户列表
* @param userTypeEnum 全局用户类型
*/
List<SysSocialUserDO> getAllSocialUserList(Integer type, String unionId, UserTypeEnum userTypeEnum);
@@ -58,6 +58,7 @@ public interface SysSocialService {
*
* @param userId 用户编号
* @return 社交用户列表
* @param userTypeEnum 全局用户类型
*/
List<SysSocialUserDO> getSocialUserList(Long userId, UserTypeEnum userTypeEnum);
@@ -67,6 +68,7 @@ public interface SysSocialService {
* @param userId 用户编号
* @param type 社交平台的类型 {@link SysSocialTypeEnum}
* @param authUser 授权用户
* @param userTypeEnum 全局用户类型
*/
void bindSocialUser(Long userId, Integer type, AuthUser authUser, UserTypeEnum userTypeEnum);
@@ -76,8 +78,8 @@ public interface SysSocialService {
* @param userId 用户编号
* @param type 社交平台的类型 {@link SysSocialTypeEnum}
* @param unionId 社交平台的 unionId
* @param userTypeEnum 全局用户类型
*/
void unbindSocialUser(Long userId, Integer type, String unionId,UserTypeEnum userTypeEnum);
// TODO @timfruit逗号后面要有空格缺少了 @userTypeEnum 的注释都补充下哈
void unbindSocialUser(Long userId, Integer type, String unionId, UserTypeEnum userTypeEnum);
}

View File

@@ -2,10 +2,10 @@ package cn.iocoder.yudao.coreservice.modules.system.service.social.impl;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.social.SysSocialUserMapper;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.social.SysSocialUserCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.dal.redis.social.SysSocialAuthUserRedisDAO;
import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialCoreService;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
@@ -38,7 +38,7 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString
@Service
@Validated
@Slf4j
public class SysSocialServiceImpl implements SysSocialService {
public class SysSocialCoreServiceImpl implements SysSocialCoreService {
@Resource
private AuthRequestFactory authRequestFactory;
@@ -47,7 +47,7 @@ public class SysSocialServiceImpl implements SysSocialService {
private SysSocialAuthUserRedisDAO authSocialUserRedisDAO;
@Resource
private SysSocialUserMapper socialUserMapper;
private SysSocialUserCoreMapper socialUserMapper;
@Override
public String getAuthorizeUrl(Integer type, String redirectUri) {

View File

@@ -0,0 +1,11 @@
package cn.iocoder.yudao.coreservice.modules.system.service.tenant;
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
/**
* 租户 Service 接口
*
* @author 芋道源码
*/
public interface SysTenantCoreService extends TenantFrameworkService {
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.coreservice.modules.system.service.tenant.impl;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.tenant.SysTenantCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.service.tenant.SysTenantCoreService;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 租户 Service 实现类
*
* @author 芋道源码
*/
@Service
public class SysTenantCoreServiceImpl implements SysTenantCoreService {
@Resource
private SysTenantCoreMapper tenantCoreMapper;
@Override
public List<Long> getTenantIds() {
List<SysTenantDO> tenants = tenantCoreMapper.selectList();
return CollectionUtils.convertList(tenants, SysTenantDO::getId);
}
}

View File

@@ -90,3 +90,6 @@ yudao:
base-package: cn.iocoder.yudao.adminserver
core-service:
base-package: cn.iocoder.yudao.coreservice
pay:
pay-notify-url: http://niubi.natapp1.cc/api/pay/order/notify
refund-notify-url: http://niubi.natapp1.cc/api/pay/refund/notify

View File

@@ -42,7 +42,10 @@ public class SysUserSessionCoreServiceTest extends BaseDbAndRedisUnitTest {
// 准备参数
String userIp = randomString();
String userAgent = randomString();
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setUserType(randomEle(UserTypeEnum.values()).getValue()));
LoginUser loginUser = randomPojo(LoginUser.class, o -> {
o.setUserType(randomEle(UserTypeEnum.values()).getValue());
o.setTenantId(0L); // 租户设置为 0因为暂未启用多租户组件
});
// mock 方法
when(securityProperties.getSessionTimeout()).thenReturn(Duration.ofDays(1));

View File

@@ -0,0 +1,171 @@
package cn.iocoder.yudao.coreservice.modules.system.service.social;
import cn.iocoder.yudao.coreservice.BaseDbAndRedisUnitTest;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.social.SysSocialUserCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.dal.redis.social.SysSocialAuthUserRedisDAO;
import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
import cn.iocoder.yudao.coreservice.modules.system.service.social.impl.SysSocialCoreServiceImpl;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import com.xkcoding.justauth.AuthRequestFactory;
import me.zhyd.oauth.model.AuthUser;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.util.List;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.hutool.core.util.RandomUtil.randomString;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* {@link SysSocialCoreServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import({SysSocialCoreServiceImpl.class, SysSocialAuthUserRedisDAO.class})
public class SysSocialCoreServiceTest extends BaseDbAndRedisUnitTest {
@Resource
private SysSocialCoreServiceImpl socialService;
@Resource
private SysSocialUserCoreMapper socialUserMapper;
@MockBean
private AuthRequestFactory authRequestFactory;
/**
* 情况一,创建 SysSocialUserDO 的情况
*/
@Test
public void testBindSocialUser_create() {
// mock 数据
// 准备参数
Long userId = randomLongId();
Integer type = randomEle(SysSocialTypeEnum.values()).getType();
AuthUser authUser = randomPojo(AuthUser.class);
// mock 方法
// 调用
socialService.bindSocialUser(userId, type, authUser, UserTypeEnum.ADMIN);
// 断言
List<SysSocialUserDO> socialUsers = socialUserMapper.selectList("user_id", userId);
assertEquals(1, socialUsers.size());
assertBindSocialUser(socialUsers.get(0), authUser, userId, type);
}
/**
* 情况二,更新 SysSocialUserDO 的情况
*/
@Test
public void testBindSocialUser_update() {
// mock 数据
SysSocialUserDO dbSocialUser = randomPojo(SysSocialUserDO.class, socialUserDO -> {
socialUserDO.setUserType(UserTypeEnum.ADMIN.getValue());
socialUserDO.setType(randomEle(SysSocialTypeEnum.values()).getType());
});
socialUserMapper.insert(dbSocialUser);
// 准备参数
Long userId = dbSocialUser.getUserId();
Integer type = dbSocialUser.getType();
AuthUser authUser = randomPojo(AuthUser.class);
// mock 方法
// 调用
socialService.bindSocialUser(userId, type, authUser, UserTypeEnum.ADMIN);
// 断言
List<SysSocialUserDO> socialUsers = socialUserMapper.selectList("user_id", userId);
assertEquals(1, socialUsers.size());
assertBindSocialUser(socialUsers.get(0), authUser, userId, type);
}
/**
* 情况一和二都存在的,逻辑二的场景
*/
@Test
public void testBindSocialUser_userId() {
// mock 数据
SysSocialUserDO dbSocialUser = randomPojo(SysSocialUserDO.class, socialUserDO -> {
socialUserDO.setUserType(UserTypeEnum.ADMIN.getValue());
socialUserDO.setType(randomEle(SysSocialTypeEnum.values()).getType());
});
socialUserMapper.insert(dbSocialUser);
// 准备参数
Long userId = randomLongId();
Integer type = dbSocialUser.getType();
AuthUser authUser = randomPojo(AuthUser.class);
// mock 方法
// 调用
socialService.bindSocialUser(userId, type, authUser, UserTypeEnum.ADMIN);
// 断言
List<SysSocialUserDO> socialUsers = socialUserMapper.selectList("user_id", userId);
assertEquals(1, socialUsers.size());
}
private void assertBindSocialUser(SysSocialUserDO socialUser, AuthUser authUser, Long userId,
Integer type) {
assertEquals(authUser.getToken().getAccessToken(), socialUser.getToken());
assertEquals(toJsonString(authUser.getToken()), socialUser.getRawTokenInfo());
assertEquals(authUser.getNickname(), socialUser.getNickname());
assertEquals(authUser.getAvatar(), socialUser.getAvatar());
assertEquals(toJsonString(authUser.getRawUserInfo()), socialUser.getRawUserInfo());
assertEquals(userId, socialUser.getUserId());
assertEquals(UserTypeEnum.ADMIN.getValue(), socialUser.getUserType());
assertEquals(type, socialUser.getType());
assertEquals(authUser.getUuid(), socialUser.getOpenid());
assertEquals(socialService.getAuthUserUnionId(authUser), socialUser.getUnionId());
}
/**
* 情况一,如果新老的 unionId 是一致的,无需解绑
*/
@Test
public void testUnbindOldSocialUser_no() {
// mock 数据
SysSocialUserDO oldSocialUser = randomPojo(SysSocialUserDO.class, socialUserDO -> {
socialUserDO.setUserType(UserTypeEnum.ADMIN.getValue());
socialUserDO.setType(randomEle(SysSocialTypeEnum.values()).getType());
});
socialUserMapper.insert(oldSocialUser);
// 准备参数
Long userId = oldSocialUser.getUserId();
Integer type = oldSocialUser.getType();
String newUnionId = oldSocialUser.getUnionId();
// 调用
socialService.unbindOldSocialUser(userId, type, newUnionId, UserTypeEnum.ADMIN);
// 断言
assertEquals(1L, socialUserMapper.selectCount(null).longValue());
}
/**
* 情况二,如果新老的 unionId 不一致的,需解绑
*/
@Test
public void testUnbindOldSocialUser_yes() {
// mock 数据
SysSocialUserDO oldSocialUser = randomPojo(SysSocialUserDO.class, socialUserDO -> {
socialUserDO.setUserType(UserTypeEnum.ADMIN.getValue());
socialUserDO.setType(randomEle(SysSocialTypeEnum.values()).getType());
});
socialUserMapper.insert(oldSocialUser);
// 准备参数
Long userId = oldSocialUser.getUserId();
Integer type = oldSocialUser.getType();
String newUnionId = randomString(10);
// 调用
socialService.unbindOldSocialUser(userId, type, newUnionId, UserTypeEnum.ADMIN);
// 断言
assertEquals(0L, socialUserMapper.selectCount(null).longValue());
}
}

View File

@@ -6,6 +6,12 @@ spring:
--- #################### 数据库相关配置 ####################
spring:
# sql:
# init:
# schema-locations: classpath:sql/create_tables.sql
# username: sa
# password:
# enabled: true
# 数据源配置项
datasource:
name: ruoyi-vue-pro
@@ -23,6 +29,9 @@ spring:
host: 127.0.0.1 # 地址
port: 16379 # 端口(单元测试,使用 16379 端口)
database: 0 # 数据库索引
integration:
jdbc:
initialize-schema:
mybatis:
lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试

View File

@@ -8,3 +8,4 @@ DELETE FROM "sys_user_session";
DELETE FROM "sys_dict_data";
DELETE FROM "sys_sms_template";
DELETE FROM "sys_sms_log";
DELETE FROM "sys_social_user";

View File

@@ -9,6 +9,7 @@ CREATE TABLE IF NOT EXISTS "inf_file" (
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '文件表';
@@ -27,6 +28,7 @@ CREATE TABLE IF NOT EXISTS `sys_user_session` (
`updater` varchar(64) DEFAULT '' ,
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY (`id`)
) COMMENT '用户在线 Session';
@@ -67,6 +69,7 @@ CREATE TABLE IF NOT EXISTS "inf_api_access_log" (
"updater" varchar(64) default '',
"update_time" timestamp not null default current_timestamp,
"deleted" bit not null default false,
"tenant_id" bigint not null default '0',
primary key ("id")
) COMMENT 'API 访问日志表';
@@ -98,6 +101,7 @@ CREATE TABLE IF NOT EXISTS "inf_api_error_log" (
"updater" varchar(64) default '',
"update_time" timestamp not null default current_timestamp,
"deleted" bit not null default false,
"tenant_id" bigint not null default '0',
primary key ("id")
) COMMENT '系统异常日志';
@@ -151,6 +155,7 @@ CREATE TABLE IF NOT EXISTS "sys_sms_log" (
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '短信日志';
@@ -169,5 +174,26 @@ CREATE TABLE IF NOT EXISTS `sys_login_log` (
`updater` varchar(64) DEFAULT '',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`deleted` bit(1) NOT NULL DEFAULT '0',
"tenant_id" bigint not null default '0',
PRIMARY KEY (`id`)
) COMMENT ='系统访问记录';
CREATE TABLE IF NOT EXISTS "sys_social_user" (
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"user_id" bigint NOT NULL,
"user_type" tinyint NOT NULL DEFAULT '0',
"type" tinyint NOT NULL,
"openid" varchar(32) NOT NULL,
"token" varchar(256) DEFAULT NULL,
"union_id" varchar(32) NOT NULL,
"raw_token_info" varchar(1024) NOT NULL,
"nickname" varchar(32) NOT NULL,
"avatar" varchar(255) DEFAULT NULL,
"raw_user_info" varchar(1024) NOT NULL,
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '社交用户';