多模块重构 4:system 模块的调整,实现 social API~~

This commit is contained in:
YunaiV
2022-01-30 21:23:45 +08:00
parent ab6ec2f0ed
commit add08b1ecd
132 changed files with 1649 additions and 1587 deletions

View File

@ -21,6 +21,20 @@
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<optional>true</optional>
</dependency>
<!-- 用户信息 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,56 @@
package cn.iocoder.yudao.module.system.api.auth;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 在线用户 Session API 接口
*
* @author 芋道源码
*/
public interface UserSessionApi {
/**
* 创建在线用户 Session
*
* @param loginUser 登录用户
* @param userIp 用户 IP
* @param userAgent 用户 UA
* @return Session 编号
*/
String createUserSession(@NotNull(message = "登录用户不能为空") LoginUser loginUser, String userIp, String userAgent);
/**
* 刷新在线用户 Session 的更新时间
*
* @param sessionId Session 编号
* @param loginUser 登录用户
*/
void refreshUserSession(@NotEmpty(message = "Session编号不能为空") String sessionId,
@NotNull(message = "登录用户不能为空") LoginUser loginUser);
/**
* 删除在线用户 Session
*
* @param sessionId Session 编号
*/
void deleteUserSession(String sessionId);
/**
* 获得 Session 编号对应的在线用户
*
* @param sessionId Session 编号
* @return 在线用户
*/
LoginUser getLoginUser(String sessionId);
/**
* 获得 Session 超时时间,单位:毫秒
*
* @return 超时时间
*/
Long getSessionTimeoutMillis();
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.api.logger;
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
import javax.validation.Valid;
/**
* 登录日志的 API 接口
*
* @author 芋道源码
*/
public interface LoginLogApi {
/**
* 创建登录日志
*
* @param reqDTO 日志信息
*/
void createLoginLog(@Valid LoginLogCreateReqDTO reqDTO);
}

View File

@ -0,0 +1,62 @@
package cn.iocoder.yudao.module.system.api.logger.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
* 登录日志创建 Request DTO
*
* @author 芋道源码
*/
@Data
public class LoginLogCreateReqDTO {
/**
* 日志类型
*/
@NotNull(message = "日志类型不能为空")
private Integer logType;
/**
* 链路追踪编号
*/
@NotEmpty(message = "链路追踪编号不能为空")
private String traceId;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*/
@NotNull(message = "用户类型不能为空")
private Integer userType;
/**
* 用户账号
*/
@NotBlank(message = "用户账号不能为空")
@Size(max = 30, message = "用户账号长度不能超过30个字符")
private String username;
/**
* 登录结果
*/
@NotNull(message = "登录结果不能为空")
private Integer result;
/**
* 用户 IP
*/
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
/**
* 浏览器 UserAgent
*/
@NotEmpty(message = "浏览器 UserAgent 不能为空")
private String userAgent;
}

View File

@ -0,0 +1,4 @@
/**
* System API 包,定义暴露给其它模块的 API
*/
package cn.iocoder.yudao.module.system.api;

View File

@ -0,0 +1,64 @@
package cn.iocoder.yudao.module.system.api.social;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
import cn.iocoder.yudao.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 绑定信息
*/
void bindSocialUser(@Valid SocialUserBindReqDTO reqDTO);
/**
* 取消绑定社交用户
*
* @param reqDTO 解绑
*/
void unbindSocialUser(@Valid SocialUserUnbindReqDTO reqDTO);
/**
* 校验社交用户的认证信息是否正确
* 如果校验不通过,则抛出 {@link ServiceException} 业务异常
*
* @param type 社交平台的类型
* @param code 授权码
* @param state state
*/
void checkSocialUser(Integer type, String code, String state);
/**
* 获得社交用户的绑定用户编号
* 注意,返回的是 MemberUser 或者 AdminUser 的 id 编号!
* 该方法会执行和 {@link #checkSocialUser(Integer, String, String)} 一样的逻辑。
* 所以在认证信息不正确的情况下,也会抛出 {@link ServiceException} 业务异常
*
* @param userType 用户类型
* @param type 社交平台的类型
* @param code 授权码
* @param state state
* @return 绑定用户编号
*/
Long getBindUserId(Integer userType, Integer type, String code, String state);
}

View File

@ -0,0 +1,48 @@
package cn.iocoder.yudao.module.system.api.social.dto;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 取消绑定社交用户 Request DTO
*
* @author 芋道源码
*/
@Data
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
*/
@NotEmpty(message = "state 不能为空")
private String state;
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.system.api.social.dto;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.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;
}

View File

@ -87,12 +87,31 @@ public interface ErrorCodeConstants {
ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002011000, "短信模板不存在");
ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1002011001, "已经存在编码为【{}】的短信模板");
// ========== 租户模块 1002012000 ==========
ErrorCode TENANT_NOT_EXISTS = new ErrorCode(1002012000, "租户不存在");
// ========== 短信发送 1002012000 ==========
ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002012000, "手机号不存在");
ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1002012001, "模板参数({})缺失");
ErrorCode SMS_SEND_TEMPLATE_NOT_EXISTS = new ErrorCode(1002012002, "短信模板不存在");
// ========== 错误码模块 1002013000 ==========
ErrorCode ERROR_CODE_NOT_EXISTS = new ErrorCode(1002013000, "错误码不存在");
ErrorCode ERROR_CODE_DUPLICATE = new ErrorCode(1002013001, "已经存在编码为【{}】的错误码");
// ========== 短信验证码 1002013000 ==========
ErrorCode SMS_CODE_NOT_FOUND = new ErrorCode(1002013000, "验证码不存在");
ErrorCode SMS_CODE_EXPIRED = new ErrorCode(1002013001, "验证码已过期");
ErrorCode SMS_CODE_USED = new ErrorCode(1002013002, "验证码已使用");
ErrorCode SMS_CODE_NOT_CORRECT = new ErrorCode(1002013004, "验证码不正确");
ErrorCode SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1002013005, "超过每日短信发送数量");
ErrorCode SMS_CODE_SEND_TOO_FAST = new ErrorCode(1002013006, "短信发送过于频率");
ErrorCode SMS_CODE_IS_EXISTS = new ErrorCode(1002013007, "手机号已被使用");
ErrorCode SMS_CODE_IS_UNUSED = new ErrorCode(1002013008, "验证码未被使用");
// ========== 租户模块 1002014000 ==========
ErrorCode TENANT_NOT_EXISTS = new ErrorCode(1002014000, "租户不存在");
// ========== 错误码模块 1002015000 ==========
ErrorCode ERROR_CODE_NOT_EXISTS = new ErrorCode(1002015000, "错误码不存在");
ErrorCode ERROR_CODE_DUPLICATE = new ErrorCode(1002015001, "已经存在编码为【{}】的错误码");
// ========== 社交用户 1002015000 ==========
ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1002015000, "社交授权失败,原因是:{}");
ErrorCode SOCIAL_USER_UNBIND_NOT_SELF = new ErrorCode(1002015001, "社交解绑失败,非当前用户绑定");
ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1002015001, "社交授权失败,找不到对应的用户");
}

View File

@ -1,37 +0,0 @@
package cn.iocoder.yudao.module.system.enums;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/**
* System 错误码枚举类
*
* system 系统,使用 1-006-000-000 段
*/
public interface SysErrorCodeConstants {
// ========== 短信发送 1006000000 ==========
ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1006000000, "手机号不存在");
ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1006000001, "模板参数({})缺失");
ErrorCode SMS_SEND_TEMPLATE_NOT_EXISTS = new ErrorCode(1006000000, "短信模板不存在");
// ========== 社交模块 1006002000 ==========
ErrorCode SOCIAL_AUTH_FAILURE = new ErrorCode(1006002000, "社交授权失败,原因是:{}");
ErrorCode SOCIAL_UNBIND_NOT_SELF = new ErrorCode(1006002001, "社交解绑失败,非当前用户绑定");
// ========== 用户模块 1006003000 ==========
ErrorCode USER_NOT_EXISTS = new ErrorCode(1006003000, "用户不存在");
ErrorCode USER_IS_DISABLE = new ErrorCode(1006003001, "名字为【{}】的用户已被禁用");
// ========== 部门模块 1006004000 ==========
ErrorCode DEPT_NOT_FOUND = new ErrorCode(1006004000, "当前部门不存在");
ErrorCode DEPT_NOT_ENABLE = new ErrorCode(1006004001, "部门不处于开启状态,不允许选择");
// ========== 角色模块 1006005000 ==========
ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1006005000, "角色不存在");
ErrorCode ROLE_IS_DISABLE = new ErrorCode(1006005001, "名字为【{}】的角色已被禁用");
// ========== 岗位模块 1006007000 ==========
ErrorCode POST_NOT_FOUND = new ErrorCode(1006007000, "当前岗位不存在");
ErrorCode POST_NOT_ENABLE = new ErrorCode(1006007001, "岗位({}) 不处于开启状态,不允许选择");
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.system.enums.logger;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 登录日志的类型枚举
*/
@Getter
@AllArgsConstructor
public enum LoginLogTypeEnum {
LOGIN_USERNAME(100), // 使用账号登录
LOGIN_SOCIAL(101), // 使用社交登录
LOGIN_MOCK(102), // 使用 Mock 登录
LOGIN_MOBILE(103), // 使用手机登陆
LOGIN_SMS(104), // 使用短信登陆
LOGOUT_SELF(200), // 自己主动登出
LOGOUT_TIMEOUT(201), // 超时登出
LOGOUT_DELETE(202), // 强制退出
;
/**
* 日志类型
*/
private final Integer type;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.enums.logger;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 登录结果的枚举类
*/
@Getter
@AllArgsConstructor
public enum LoginResultEnum {
SUCCESS(0), // 成功
BAD_CREDENTIALS(10), // 账号或密码不正确
USER_DISABLED(20), // 用户被禁用
CAPTCHA_NOT_FOUND(30), // 图片验证码不存在
CAPTCHA_CODE_ERROR(31), // 图片验证码不正确
UNKNOWN_ERROR(100), // 未知异常
;
/**
* 结果
*/
private final Integer result;
}

View File

@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.system.enums.sms;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 用户短信验证码发送场景的枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum SmsSceneEnum implements IntArrayValuable {
MEMBER_LOGIN(1, "user-sms-login", "会员用户 - 手机号登陆"),
MEMBER_UPDATE_MOBILE(2, "user-sms-reset-password", "会员用户 - 修改手机"),
MEMBER_FORGET_PASSWORD(3, "user-sms-update-mobile", "会员用户 - 忘记密码");
// 如果未来希望管理后台支持手机验证码登陆,可以通过添加 ADMIN_MEMBER_LOGIN 枚举
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SmsSceneEnum::getScene).toArray();
/**
* 验证场景的编号
*/
private final Integer scene;
/**
* 模版编码
*/
private final String templateCode;
/**
* 描述
*/
private final String description;
@Override
public int[] array() {
return ARRAYS;
}
public static SmsSceneEnum getCodeByScene(Integer scene) {
return ArrayUtil.firstMatch(sceneEnum -> sceneEnum.getScene().equals(scene));
}
}