【升级】v3.5.0后端更新,更新日志见推文

pull/257/head v3.5.0
xuyuxiang 2025-05-13 01:33:37 +08:00
parent 550a118068
commit 9dd127479a
422 changed files with 13368 additions and 2033 deletions

54
pom.xml
View File

@ -245,21 +245,28 @@
<version>3.3.3</version>
</dependency>
<!-- Sa-token-core -->
<!-- json-flattener -->
<dependency>
<groupId>com.github.wnameless.json</groupId>
<artifactId>json-flattener</artifactId>
<version>0.16.4</version>
</dependency>
<!-- sa-token-core -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>1.37.0</version>
</dependency>
<!-- Sa-token -->
<!-- sa-token -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>1.37.0</version>
</dependency>
<!-- Sa-token 整合 redis 使用jackson序列化方式 -->
<!-- sa-token 整合 redis 使用jackson序列化方式 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
@ -343,25 +350,18 @@
<version>3.1.944</version>
</dependency>
<!--阿里云短信sdk-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>2.0.24</version>
</dependency>
<!--腾讯云短信sdk-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-sms</artifactId>
<version>3.1.893</version>
</dependency>
<!-- sms4j短信sdk -->
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-javase-plugin</artifactId>
<version>3.1.1</version>
<version>3.3.4</version>
</dependency>
<!-- sms4j消息推送sdk -->
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-oa-core</artifactId>
<version>3.3.4</version>
</dependency>
<!--系统硬件信息-->
@ -371,6 +371,14 @@
<version>6.4.11</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.1</version>
<scope>test</scope>
</dependency>
<!-- dynamic-datasource -->
<dependency>
<groupId>com.baomidou</groupId>
@ -432,7 +440,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.12.1</version>
<version>3.7.0</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
@ -461,11 +469,19 @@
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>_sql/*</exclude>
<exclude>*.md</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.ttf</include>
<include>**/*.ttc</include>
<include>**/*.TTF</include>
<include>**/*.TTC</include>
</includes>
</resource>
</resources>

View File

@ -129,5 +129,11 @@
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<!-- json-flattener -->
<dependency>
<groupId>com.github.wnameless.json</groupId>
<artifactId>json-flattener</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -58,21 +58,13 @@ public class CommonCacheOperator {
public Collection<String> getAllKeys() {
Set<String> keys = redisTemplate.keys(CACHE_KEY_PREFIX + "*");
if (keys != null) {
// 去掉缓存key的common prefix前缀
return keys.stream().map(key -> StrUtil.removePrefix(key, CACHE_KEY_PREFIX)).collect(Collectors.toSet());
} else {
return CollectionUtil.newHashSet();
}
// 去掉缓存key的common prefix前缀
return keys.stream().map(key -> StrUtil.removePrefix(key, CACHE_KEY_PREFIX)).collect(Collectors.toSet());
}
public Collection<Object> getAllValues() {
Set<String> keys = redisTemplate.keys(CACHE_KEY_PREFIX + "*");
if (keys != null) {
return redisTemplate.opsForValue().multiGet(keys);
} else {
return CollectionUtil.newArrayList();
}
return redisTemplate.opsForValue().multiGet(keys);
}
public Map<String, Object> getAllKeyValues() {
@ -86,8 +78,6 @@ public class CommonCacheOperator {
public void removeBatch(String pattern) {
Set<String> keys = redisTemplate.keys(CACHE_KEY_PREFIX + pattern);
if (keys != null) {
redisTemplate.delete(keys);
}
redisTemplate.delete(keys);
}
}

View File

@ -13,7 +13,8 @@
package vip.xiaonuo.common.consts;
/**
* @description
*
*
* @author dongxiayu
* @date 2023/1/30 0:44
**/

View File

@ -42,8 +42,4 @@ public enum CommonSortOrderEnum {
throw new CommonException("不支持该排序方式:{}", value);
}
}
public String getValue() {
return value.toLowerCase();
}
}

View File

@ -42,20 +42,20 @@ public class CommonSm4CbcTypeHandler<T> extends BaseTypeHandler<T> {
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
String columnValue = rs.getString(columnName);
//有一些可能是空字符
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T)CommonCryptogramUtil.doSm4CbcDecrypt(columnValue);
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T) CommonCryptogramUtil.doSm4CbcDecrypt(columnValue);
}
@SuppressWarnings("ALL")
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String columnValue = rs.getString(columnIndex);
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T)CommonCryptogramUtil.doSm4CbcDecrypt(columnValue);
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T) CommonCryptogramUtil.doSm4CbcDecrypt(columnValue);
}
@SuppressWarnings("ALL")
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String columnValue = cs.getString(columnIndex);
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T)CommonCryptogramUtil.doSm4CbcDecrypt(columnValue);
return StringUtils.isBlank(columnValue) ? (T)columnValue : (T) CommonCryptogramUtil.doSm4CbcDecrypt(columnValue);
}
}

View File

@ -15,6 +15,7 @@ package vip.xiaonuo.common.listener;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.Getter;
import vip.xiaonuo.common.exception.CommonException;
import java.util.ArrayList;
@ -31,15 +32,11 @@ public class CommonDataChangeEventCenter {
// --------- 注册侦听器
private static List<CommonDataChangeListener> listenerList = new ArrayList<>();
/**
*
* @return /
*/
public static List<CommonDataChangeListener> getListenerList() {
return listenerList;
}
@Getter
private static List<CommonDataChangeListener> listenerList = new ArrayList<>();
/**
*

View File

@ -56,7 +56,6 @@ public class CommonPageRequest {
}
} catch (Exception e) {
log.error(">>> 分页条数转换异常:", e);
size = 20;
}
}
@ -67,7 +66,6 @@ public class CommonPageRequest {
page = Convert.toInt(pageString);
} catch (Exception e) {
log.error(">>> 分页页数转换异常:", e);
page = 1;
}
}
Page<T> objectPage = new Page<>(page, size);

View File

@ -13,7 +13,9 @@
package vip.xiaonuo.common.pojo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import java.io.Serial;
import java.io.Serializable;
/**
@ -23,6 +25,7 @@ import java.io.Serializable;
* @date 2022/8/15 16:08
**/
public class CommonResult<T> implements Serializable{
@Serial
private static final long serialVersionUID = 1L;
public static final int CODE_SUCCESS = 200;
public static final int CODE_ERROR = 500;
@ -30,9 +33,17 @@ public class CommonResult<T> implements Serializable{
@Schema(description = "状态码")
private int code;
/**
* msg
*/
@Getter
@Schema(description = "提示语")
private String msg;
/**
* data
*/
@Getter
@Schema(description = "返回数据")
private T data;
@ -53,21 +64,6 @@ public class CommonResult<T> implements Serializable{
return this.code;
}
/**
* msg
* @return msg
*/
public String getMsg() {
return this.msg;
}
/**
* data
* @return data
*/
public T getData() {
return this.data;
}
/**
* code
* @param code code

View File

@ -29,9 +29,6 @@ import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "snowy.config.common")
public class CommonProperties {
/** 前端地址 */
private String frontUrl;
/** 后端地址 */
private String backendUrl;
}

View File

@ -19,7 +19,7 @@ import com.antherd.smcrypto.sm4.Sm4Options;
import lombok.extern.slf4j.Slf4j;
/**
* 使 https://github.com/antherd/sm-crypto 项目中一些加解密方式
* 使 <a href="https://github.com/antherd/sm-crypto">sm-crypto</a>
* 使使
* sm-crypto
*

View File

@ -30,8 +30,8 @@ public class CommonEmailUtil {
* @author xuyuxiang
* @date 2022/8/15 13:32
**/
public static boolean isEmail(String email) {
return Validator.isEmail(email);
public static boolean isNotEmail(String email) {
return !Validator.isEmail(email);
}
/**
@ -42,7 +42,7 @@ public class CommonEmailUtil {
**/
public static void validEmail(String emails) {
StrUtil.split(emails, StrUtil.COMMA).forEach(email -> {
if(!isEmail(email)) {
if(isNotEmail(email)) {
throw new CommonException("邮件地址:{}格式错误", email);
}
});

View File

@ -26,7 +26,7 @@ import java.io.InputStream;
/**
* ip线
* https://gitee.com/lionsoul/ip2region/tree/master/binding/java
* <a href="https://gitee.com/lionsoul/ip2region/tree/master/binding/java">ip2region</a>
*
* @author xuyuxiang
* @date 2020/3/16 11:25

View File

@ -77,29 +77,15 @@ public class CommonTimeFormatUtil {
String weekday;
//获取是本周的第几天
int dayOfWeek = DateUtil.dayOfWeek(date) - 1;
switch (dayOfWeek) {
case 1:
weekday = "周一";
break;
case 2:
weekday = "周二";
break;
case 3:
weekday = "周三";
break;
case 4:
weekday = "周四";
break;
case 5:
weekday = "周五";
break;
case 6:
weekday = "周六";
break;
default:
weekday = "周日";
break;
}
weekday = switch (dayOfWeek) {
case 1 -> "周一";
case 2 -> "周二";
case 3 -> "周三";
case 4 -> "周四";
case 5 -> "周五";
case 6 -> "周六";
default -> "周日";
};
//显示本周时分
return weekday + " " + DateUtil.format(date, "HH:mm");
} else {

View File

@ -27,4 +27,4 @@
<artifactId>sa-token-core</artifactId>
</dependency>
</dependencies>
</project>
</project>

View File

@ -66,6 +66,14 @@ public interface SaBaseLoginUserApi {
**/
SaBaseLoginUser getUserByPhone(String phone);
/**
* Bnull
*
* @author xuyuxiang
* @date 2022/3/10 16:14
**/
SaBaseLoginUser getUserByEmail(String email);
/**
* Cnull
*
@ -74,6 +82,14 @@ public interface SaBaseLoginUserApi {
**/
SaBaseClientLoginUser getClientUserByPhone(String phone);
/**
* Cnull
*
* @author xuyuxiang
* @date 2022/3/10 16:14
**/
SaBaseClientLoginUser getClientUserByEmail(String email);
/**
* id
*
@ -121,4 +137,44 @@ public interface SaBaseLoginUserApi {
* @date 2022/4/27 22:57
*/
void updateUserLoginInfo(String userId, String device);
/**
* 使B
*
* @author xuyuxiang
* @date 2022/3/10 16:14
**/
SaBaseLoginUser createUserWithPhone(String phone);
/**
* 使C
*
* @author xuyuxiang
* @date 2022/3/10 16:14
**/
SaBaseClientLoginUser createClientUserWithPhone(String phone);
/**
* 使B
*
* @author xuyuxiang
* @date 2022/3/10 16:14
**/
SaBaseLoginUser createUserWithEmail(String email);
/**
* 使C
*
* @author xuyuxiang
* @date 2022/3/10 16:14
**/
SaBaseClientLoginUser createClientUserWithEmail(String email);
/**
*
*
* @author xuyuxiang
* @date 2022/3/10 16:14
**/
void doRegister(String account, String password);
}

View File

@ -63,28 +63,22 @@
<artifactId>tencentcloud-sdk-java-ses</artifactId>
</dependency>
<!--阿里云短信sdk-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
</dependency>
<!--腾讯云短信sdk-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-sms</artifactId>
</dependency>
<!-- sms4j短信sdk -->
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-javase-plugin</artifactId>
</dependency>
<!-- sms4j消息推送sdk -->
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-oa-core</artifactId>
</dependency>
<!--系统硬件信息-->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
</dependency>
</dependencies>
</project>
</project>

View File

@ -27,6 +27,28 @@ import java.util.Map;
**/
public interface DevEmailApi {
/**
* TXT使
*
* @param tos
* @param subject
* @param content
* @author xuyuxiang
* @date 2022/2/7 22:29
*/
void sendDynamicTxtEmail(String tos, String subject, String content);
/**
* HTML使
*
* @param tos
* @param subject
* @param content
* @author xuyuxiang
* @date 2022/2/7 22:29
*/
void sendDynamicHtmlEmail(String tos, String subject, String content);
/* =========本地邮件========= */
/**

View File

@ -31,6 +31,14 @@ public interface DevFileApi {
**/
String uploadDynamicReturnId(MultipartFile file);
/**
* url使
*
* @author xuyuxiang
* @date 2021/10/13 14:01
**/
String uploadDynamicReturnUrl(MultipartFile file);
/* =========本地文件========= */
/**
@ -119,6 +127,7 @@ public interface DevFileApi {
*/
JSONObject getFileInfoById(String id);
/**
* id
*

View File

@ -0,0 +1,109 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.dev.api;
/**
* API
*
* @author xuyuxiang
* @date 2022/6/22 15:21
**/
public interface DevPushApi {
/**
* 使
*
* @param content
* @param noticeAll
* @author xuyuxiang
* @date 2022/2/23 14:24
*/
void pushDynamicText(String content, boolean noticeAll);
/**
* TXT
*
* @param content
* @param noticeAll
* @author xuyuxiang
* @date 2022/2/23 14:24
*/
void pushFeiShuText(String content, boolean noticeAll);
/**
* TXT
*
* @param content
* @param noticeAll
* @param phones
* @author xuyuxiang
* @date 2022/2/23 14:24
*/
void pushDingTalkText(String content, boolean noticeAll, String phones);
/**
* MARKDOWN
*
* @param title
* @param content
* @param noticeAll
* @author xuyuxiang
* @date 2022/2/23 14:24
*/
void pushDingTalkMarkdown(String title, String content, boolean noticeAll);
/**
* LINK
*
* @param title
* @param content
* @param picUrl
* @param messageUrl
* @author xuyuxiang
* @date 2022/2/23 14:24
*/
void pushDingTalkLink(String title, String content, String picUrl,String messageUrl);
/**
* TXT
*
* @param content
* @param noticeAll
* @param phones
* @author xuyuxiang
* @date 2022/2/23 14:24
*/
void pushWorkWechatText(String content, boolean noticeAll, String phones);
/**
* MARKDOWN
*
* @param title
* @param content
* @author xuyuxiang
* @date 2022/2/23 14:24
*/
void pushWorkWechatMarkdown(String title, String content);
/**
* NEWS
*
* @param title
* @param content
* @param picUrl
* @param messageUrl
* @author xuyuxiang
* @date 2022/2/23 14:24
*/
void pushWorkWechatNews(String title, String content, String picUrl,String messageUrl);
}

View File

@ -12,6 +12,8 @@
*/
package vip.xiaonuo.dev.api;
import cn.hutool.json.JSONObject;
/**
* API
*
@ -20,6 +22,17 @@ package vip.xiaonuo.dev.api;
**/
public interface DevSmsApi {
/**
* 使
*
* @param phoneNumbers
* @param templateCodeOrId id
* @param paramMap
* @author xuyuxiang
* @date 2022/2/7 22:29
*/
void sendDynamicSms(String phoneNumbers, String templateCodeOrId, JSONObject paramMap);
/* =========阿里云短信========= */
/**
@ -27,7 +40,7 @@ public interface DevSmsApi {
*
* @param phoneNumbers ,
* 1000
* @param signName 使
* @param signName
* @param templateCode
* @param templateParam JSON{"name":"张三","number":"15038****76"}
* @author xuyuxiang
@ -40,17 +53,15 @@ public interface DevSmsApi {
/**
*
*
* @param sdkAppId SdkAppId SdkAppId1400006666
* [](https://console.cloud.tencent.com/smsv2/app-manage) 查看
* @param phoneNumbers ,
* 1000
* @param signName 使
* @param signName
* @param templateCode
* @param templateParam "张三,15038****76,进行中"}
* @author xuyuxiang
* @date 2022/2/24 13:42
**/
void sendSmsTencent(String sdkAppId, String phoneNumbers, String signName, String templateCode, String templateParam);
void sendSmsTencent(String phoneNumbers, String signName, String templateCode, String templateParam);
/* =========小诺短信========= */
@ -58,10 +69,11 @@ public interface DevSmsApi {
*
*
* @param phoneNumbers ,
* @param signName 使
* @param message
* @author xuyuxiang
* @date 2022/2/24 13:42
* 1000
* @param signName
* @param message
* @author yubaoshan
* @date 2024/5/20 12:00
**/
void sendSmsXiaonuo(String phoneNumbers, String signName, String message);
}

View File

@ -0,0 +1,32 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.dev.api;
import java.util.List;
/**
* APi
*
* @author xuyuxiang
* @date 2022/6/17 10:37
**/
public interface DevWeakPasswordApi {
/**
*
*
* @author xuyuxiang
* @date 2022/6/17 11:11
**/
List<String> weakPasswordList();
}

View File

@ -0,0 +1,22 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.mobile.api;
/**
* API
*
* @author xuyuxiang
* @date 2022/9/26 14:24
**/
public interface MobileApi {
}

View File

@ -28,5 +28,5 @@ public interface MobileButtonApi {
* @author
* @date 2023/2/5 13:26
**/
List<String> listByIds(List<String> idList);
List<String> listButtonCodeListByIdList(List<String> idList);
}

View File

@ -33,6 +33,14 @@ public interface MobileMenuApi {
**/
List<JSONObject> mobileMenuTreeSelector();
/**
*
*
* @author xuyuxiang
* @date 2023/1/31 10:10
**/
List<JSONObject> mobileMenuTreeSelector(List<JSONObject> originDataList);
/**
*
*

View File

@ -0,0 +1,30 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.sys.api;
/**
* API
*
* @author xuyuxiang
* @date 2022/9/26 14:24
**/
public interface SysApi {
/**
*
*
* @author xuyuxiang
* @date 2022/9/26 14:25
**/
String getDefaultPassword();
}

View File

@ -13,6 +13,7 @@
package vip.xiaonuo.sys.api;
import cn.hutool.json.JSONObject;
import java.util.List;
/**

View File

@ -37,5 +37,5 @@ public interface SysPositionApi {
* @author xuyuxiang
* @date 2022/7/22 14:47
**/
Page<JSONObject> positionSelector(String orgId, String searchKey);
Page<JSONObject> positionSelector(String orgId, String searchKey, Integer current, Integer size);
}

View File

@ -48,4 +48,20 @@ public interface SysRoleApi {
* @date 2022/11/1 15:58
**/
void grantForGenMenuAndButton(String menuId);
/**
*
*
* @author xuyuxiang
* @date 2022/4/24 20:08
*/
List<JSONObject> resourceTreeSelector();
/**
*
*
* @author xuyuxiang
* @date 2022/4/24 20:08
*/
List<String> permissionTreeSelector();
}

View File

@ -17,7 +17,8 @@ import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.strategy.SaStrategy;
import cn.hutool.json.JSONUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@ -71,6 +72,7 @@ public class AuthConfigure implements WebMvcConfigurer {
@Bean("stpClientLogic")
public StpLogic getStpClientLogic(SaTokenConfig saTokenConfig) {
// 重写Sa-Token的StpLogic默认客户端类型为C
return new StpLogic(SaClientTypeEnum.C.getValue()).setConfig(saTokenConfig);
}
@ -105,7 +107,12 @@ public class AuthConfigure implements WebMvcConfigurer {
} else {
permissionListObject = commonCacheOperator.get(CacheConstant.AUTH_C_PERMISSION_LIST_CACHE_KEY + loginId);
}
return JSONUtil.parseArray(permissionListObject).toList(String.class);
// 转为字符串
String permissionListString = permissionListObject.toString();
// 去除首尾的方括号
String trimmedStr = StrUtil.sub(permissionListString, 1, -1);
// 使用逗号和空格分割字符串,并转换为列表
return CollectionUtil.newArrayList(StrUtil.split(trimmedStr, ", "));
}
/**

View File

@ -0,0 +1,48 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.auth.core.util;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import vip.xiaonuo.dev.api.DevConfigApi;
/**
*
*
* @author xuyuxiang
* @date 2025/3/21 19:07
**/
public class AuthEmailFormatUtl {
/** 系统名称 */
private static final String SNOWY_SYS_NAME_KEY = "SNOWY_SYS_NAME";
/**
*
*
* @author xuyuxiang
* @date 2025/3/21 19:08
**/
public static String format(String content, JSONObject paramMap) {
DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
// 获取系统名称
String sysName = devConfigApi.getValueByKey(SNOWY_SYS_NAME_KEY);
// 系统名称
paramMap.set("sysName", sysName);
// 当前时间
paramMap.set("sysNowTime", DateUtil.now());
return StrUtil.format(content, paramMap);
}
}

View File

@ -18,6 +18,12 @@ import lombok.extern.slf4j.Slf4j;
import vip.xiaonuo.common.pojo.CommonResult;
import vip.xiaonuo.common.util.CommonServletUtil;
/**
*
*
* @author xuyuxiang
* @date 2021/10/9 14:24
**/
@Slf4j
public class AuthExceptionUtil {

View File

@ -12,10 +12,11 @@
*/
package vip.xiaonuo.auth.modular.login.controller;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@ -28,10 +29,13 @@ import vip.xiaonuo.auth.core.util.StpClientUtil;
import vip.xiaonuo.auth.modular.login.param.AuthAccountPasswordLoginParam;
import vip.xiaonuo.auth.modular.login.param.AuthGetPhoneValidCodeParam;
import vip.xiaonuo.auth.modular.login.param.AuthPhoneValidCodeLoginParam;
import vip.xiaonuo.auth.modular.login.param.AuthRegisterParam;
import vip.xiaonuo.auth.modular.login.result.AuthPicValidCodeResult;
import vip.xiaonuo.auth.modular.login.service.AuthService;
import vip.xiaonuo.common.pojo.CommonResult;
import javax.validation.Valid;
/**
* C
*
@ -39,6 +43,7 @@ import vip.xiaonuo.common.pojo.CommonResult;
* @date 2021/12/23 21:50
*/
@Tag(name = "C端登录控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 1)
@RestController
@Validated
public class AuthClientController {
@ -52,6 +57,7 @@ public class AuthClientController {
* @author xuyuxiang
* @date 2022/7/8 9:26
**/
@ApiOperationSupport(order = 1)
@Operation(summary = "C端获取图片验证码")
@GetMapping("/auth/c/getPicCaptcha")
public CommonResult<AuthPicValidCodeResult> getPicCaptcha() {
@ -64,6 +70,7 @@ public class AuthClientController {
* @author xuyuxiang
* @date 2022/7/8 9:26
**/
@ApiOperationSupport(order = 2)
@Operation(summary = "C端获取手机验证码")
@GetMapping("/auth/c/getPhoneValidCode")
public CommonResult<String> getPhoneValidCode(@Valid AuthGetPhoneValidCodeParam authGetPhoneValidCodeParam) {
@ -76,6 +83,7 @@ public class AuthClientController {
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 3)
@Operation(summary = "C端账号密码登录")
@PostMapping("/auth/c/doLogin")
public CommonResult<String> doLogin(@RequestBody @Valid AuthAccountPasswordLoginParam authAccountPasswordLoginParam) {
@ -88,6 +96,7 @@ public class AuthClientController {
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 4)
@Operation(summary = "C端手机验证码登录")
@PostMapping("/auth/c/doLoginByPhone")
public CommonResult<String> doLoginByPhone(@RequestBody @Valid AuthPhoneValidCodeLoginParam authPhoneValidCodeLoginParam) {
@ -100,6 +109,7 @@ public class AuthClientController {
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 5)
@Operation(summary = "C端退出")
@SaClientCheckLogin
@GetMapping("/auth/c/doLogout")
@ -114,10 +124,25 @@ public class AuthClientController {
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 6)
@Operation(summary = "C端获取用户信息")
@SaClientCheckLogin
@GetMapping("/auth/c/getLoginUser")
public CommonResult<SaBaseClientLoginUser> getLoginUser() {
return CommonResult.data(authService.getClientLoginUser());
}
/**
* C
*
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 7)
@Operation(summary = "C端注册")
@PostMapping("/auth/c/register")
public CommonResult<String> register(@RequestBody @Valid AuthRegisterParam authRegisterParam) {
authService.register(authRegisterParam, SaClientTypeEnum.C.getValue());
return CommonResult.ok();
}
}

View File

@ -14,10 +14,11 @@ package vip.xiaonuo.auth.modular.login.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@ -25,13 +26,13 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import vip.xiaonuo.auth.core.enums.SaClientTypeEnum;
import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
import vip.xiaonuo.auth.modular.login.param.AuthAccountPasswordLoginParam;
import vip.xiaonuo.auth.modular.login.param.AuthGetPhoneValidCodeParam;
import vip.xiaonuo.auth.modular.login.param.AuthPhoneValidCodeLoginParam;
import vip.xiaonuo.auth.modular.login.param.*;
import vip.xiaonuo.auth.modular.login.result.AuthPicValidCodeResult;
import vip.xiaonuo.auth.modular.login.service.AuthService;
import vip.xiaonuo.common.pojo.CommonResult;
import javax.validation.Valid;
/**
* B
*
@ -39,6 +40,7 @@ import vip.xiaonuo.common.pojo.CommonResult;
* @date 2021/12/23 21:50
*/
@Tag(name = "B端登录控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 2)
@RestController
@Validated
public class AuthController {
@ -52,6 +54,7 @@ public class AuthController {
* @author xuyuxiang
* @date 2022/7/8 9:26
**/
@ApiOperationSupport(order = 1)
@Operation(summary = "B端获取图片验证码")
@GetMapping("/auth/b/getPicCaptcha")
public CommonResult<AuthPicValidCodeResult> getPicCaptcha() {
@ -59,23 +62,38 @@ public class AuthController {
}
/**
* B
* B
*
* @author xuyuxiang
* @date 2022/7/8 9:26
**/
@Operation(summary = "B端获取手机验证码")
@ApiOperationSupport(order = 2)
@Operation(summary = "B端获取手机登录验证码")
@GetMapping("/auth/b/getPhoneValidCode")
public CommonResult<String> getPhoneValidCode(@Valid AuthGetPhoneValidCodeParam authGetPhoneValidCodeParam) {
return CommonResult.data(authService.getPhoneValidCode(authGetPhoneValidCodeParam, SaClientTypeEnum.B.getValue()));
}
/**
* B
*
* @author xuyuxiang
* @date 2022/7/8 9:26
**/
@ApiOperationSupport(order = 3)
@Operation(summary = "B端获取邮箱登录验证码")
@GetMapping("/auth/b/getEmailValidCode")
public CommonResult<String> getEmailValidCode(@Valid AuthGetEmailValidCodeParam authGetEmailValidCodeParam) {
return CommonResult.data(authService.getEmailValidCode(authGetEmailValidCodeParam, SaClientTypeEnum.B.getValue()));
}
/**
* B
*
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 4)
@Operation(summary = "B端账号密码登录")
@PostMapping("/auth/b/doLogin")
public CommonResult<String> doLogin(@RequestBody @Valid AuthAccountPasswordLoginParam authAccountPasswordLoginParam) {
@ -88,18 +106,33 @@ public class AuthController {
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 5)
@Operation(summary = "B端手机验证码登录")
@PostMapping("/auth/b/doLoginByPhone")
public CommonResult<String> doLoginByPhone(@RequestBody @Valid AuthPhoneValidCodeLoginParam authPhoneValidCodeLoginParam) {
return CommonResult.data(authService.doLoginByPhone(authPhoneValidCodeLoginParam, SaClientTypeEnum.B.getValue()));
}
/**
* B
*
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 6)
@Operation(summary = "B端邮箱验证码登录")
@PostMapping("/auth/b/doLoginByEmail")
public CommonResult<String> doLoginByEmail(@RequestBody @Valid AuthEmailValidCodeLoginParam authEmailValidCodeLoginParam) {
return CommonResult.data(authService.doLoginByEmail(authEmailValidCodeLoginParam, SaClientTypeEnum.B.getValue()));
}
/**
* B退
*
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 7)
@Operation(summary = "B端退出")
@SaCheckLogin
@GetMapping("/auth/b/doLogout")
@ -114,10 +147,25 @@ public class AuthController {
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 8)
@Operation(summary = "B端获取用户信息")
@SaCheckLogin
@GetMapping("/auth/b/getLoginUser")
public CommonResult<SaBaseLoginUser> getLoginUser() {
return CommonResult.data(authService.getLoginUser());
}
/**
* B
*
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 9)
@Operation(summary = "B端注册")
@PostMapping("/auth/b/register")
public CommonResult<String> register(@RequestBody @Valid AuthRegisterParam authRegisterParam) {
authService.register(authRegisterParam, SaClientTypeEnum.B.getValue());
return CommonResult.ok();
}
}

View File

@ -24,19 +24,13 @@ import vip.xiaonuo.common.exception.CommonException;
@Getter
public enum AuthDeviceTypeEnum {
/**
* PC
*/
/** PC端 */
PC("PC"),
/**
*
*/
/** 移动端 */
APP("APP"),
/**
*
*/
/** 小程序端 */
MINI("MINI");
private final String value;

View File

@ -23,59 +23,37 @@ import lombok.Getter;
@Getter
public enum AuthExceptionEnum {
/**
*
*/
/** 验证码不能为空 */
VALID_CODE_EMPTY("验证码不能为空"),
/**
*
*/
/** 验证码请求号不能为空 */
VALID_CODE_REQ_NO_EMPTY("验证码请求号不能为空"),
/**
*
*/
/** 验证码错误 */
VALID_CODE_ERROR("验证码错误"),
/**
*
*/
/** 账号错误 */
ACCOUNT_ERROR("账号错误"),
/**
*
*/
/** 账号已停用 */
ACCOUNT_DISABLED("账号已停用"),
/**
*
*/
/** 密码错误 */
PWD_ERROR("密码错误"),
/**
*
*/
/** 手机号格式错误 */
PHONE_FORMAT_ERROR("手机号格式错误"),
/**
*
*/
PHONE_ERROR("手机号不存在"),
/** 邮箱格式错误 */
EMAIL_FORMAT_ERROR("邮箱格式错误"),
/**
*
*/
/** 客户端类型不能为空 */
CLIENT_TYPE_EMPTY("客户端类型不能为空"),
/**
*
*/
/** 客户端类型错误 */
CLIENT_TYPE_ERROR("客户端类型错误"),
/**
*
*/
/** 密码解密失败,请检查前端公钥 */
PWD_DECRYPT_ERROR("密码解密失败,请检查前端公钥");
private final String value;

View File

@ -0,0 +1,45 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.auth.modular.login.enums;
import lombok.Getter;
import vip.xiaonuo.common.exception.CommonException;
/**
*
*
* @author xuyuxiang
* @date 2021/10/11 14:02
**/
@Getter
public enum AuthPhoneOrEmailTypeEnum {
/** 手机号 */
PHONE("PHONE"),
/** 邮箱 */
EMAIL("EMAIL");
private final String value;
AuthPhoneOrEmailTypeEnum(String value) {
this.value = value;
}
public static void validate(String value) {
boolean flag = PHONE.getValue().equals(value) || EMAIL.getValue().equals(value);
if(!flag) {
throw new CommonException("不支持的手机号邮箱类型:{}", value);
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.auth.modular.login.enums;
import lombok.Getter;
/**
*
*
* @author xuyuxiang
* @date 2022/6/16 16:14
**/
@Getter
public enum AuthSmsEngineTypeEnum {
/** 阿里云 */
ALIYUN("ALIYUN"),
/** 腾讯云 */
TENCENT("TENCENT"),
/** 小诺短信 */
XIAONUO("XIAONUO");
private final String value;
AuthSmsEngineTypeEnum(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.auth.modular.login.enums;
import lombok.Getter;
import vip.xiaonuo.common.exception.CommonException;
/**
*
*
* @author xuyuxiang
* @date 2021/10/11 14:02
**/
@Getter
public enum AuthStrategyWhenNoUserWithPhoneOrEmailEnum {
/** 不允许登录 */
NOT_ALLOW_LOGIN("NOT_ALLOW_LOGIN"),
/** 自动创建用户 */
AUTO_CREATE_USER("AUTO_CREATE_USER");
private final String value;
AuthStrategyWhenNoUserWithPhoneOrEmailEnum(String value) {
this.value = value;
}
public static void validate(String value) {
boolean flag = NOT_ALLOW_LOGIN.getValue().equals(value) || AUTO_CREATE_USER.getValue().equals(value);
if(!flag) {
throw new CommonException("不支持的手机号或邮箱无对应用户时策略型:{}", value);
}
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.auth.modular.login.param;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
/**
*
*
* @author xuyuxiang
* @date 2022/7/7 16:46
**/
@Getter
@Setter
public class AuthEmailValidCodeLoginParam {
/** 邮箱 */
@Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "邮箱不能为空")
private String email;
/** 验证码 */
@Schema(description = "验证码", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "验证码不能为空")
private String validCode;
/** 验证码请求号 */
@Schema(description = "验证码请求号", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "验证码请求号不能为空")
private String validCodeReqNo;
/** 设备 */
@Schema(description = "设备")
private String device;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.auth.modular.login.param;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
/**
*
*
* @author xuyuxiang
* @date 2022/8/25 13:45
**/
@Getter
@Setter
public class AuthGetEmailValidCodeParam {
/** 邮箱 */
@Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "邮箱不能为空")
private String email;
/** 验证码 */
@Schema(description = "验证码", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "验证码不能为空")
private String validCode;
/** 验证码请求号 */
@Schema(description = "验证码请求号", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "验证码请求号不能为空")
private String validCodeReqNo;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.auth.modular.login.param;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
/**
*
*
* @author xuyuxiang
* @date 2022/7/7 16:46
**/
@Getter
@Setter
public class AuthRegisterParam {
/** 账号 */
@Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "账号不能为空")
private String account;
/** 密码 */
@Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "密码不能为空")
private String password;
/** 验证码 */
@Schema(description = "验证码")
private String validCode;
/** 验证码请求号 */
@Schema(description = "验证码请求号")
private String validCodeReqNo;
}

View File

@ -14,9 +14,7 @@ package vip.xiaonuo.auth.modular.login.service;
import vip.xiaonuo.auth.core.pojo.SaBaseClientLoginUser;
import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
import vip.xiaonuo.auth.modular.login.param.AuthAccountPasswordLoginParam;
import vip.xiaonuo.auth.modular.login.param.AuthGetPhoneValidCodeParam;
import vip.xiaonuo.auth.modular.login.param.AuthPhoneValidCodeLoginParam;
import vip.xiaonuo.auth.modular.login.param.*;
import vip.xiaonuo.auth.modular.login.result.AuthPicValidCodeResult;
/**
@ -36,13 +34,21 @@ public interface AuthService {
AuthPicValidCodeResult getPicCaptcha(String type);
/**
*
*
*
* @author xuyuxiang
* @date 2021/12/28 14:46
**/
String getPhoneValidCode(AuthGetPhoneValidCodeParam authGetPhoneValidCodeParam, String type);
/**
*
*
* @author xuyuxiang
* @date 2021/12/28 14:46
**/
String getEmailValidCode(AuthGetEmailValidCodeParam authGetEmailValidCodeParam, String type);
/**
*
*
@ -59,6 +65,14 @@ public interface AuthService {
**/
String doLoginByPhone(AuthPhoneValidCodeLoginParam authPhoneValidCodeLoginParam, String type);
/**
*
*
* @author xuyuxiang
* @date 2021/12/28 14:46
**/
String doLoginByEmail(AuthEmailValidCodeLoginParam authEmailValidCodeLoginParam, String type);
/**
* B
*
@ -82,4 +96,12 @@ public interface AuthService {
* @date 2022/7/9 14:44
*/
String doLoginById(String userId, String device, String type);
/**
* C
*
* @author xuyuxiang
* @date 2022/7/9 14:44
*/
void register(AuthRegisterParam authRegisterParam, String type);
}

View File

@ -23,6 +23,7 @@ import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@ -30,14 +31,15 @@ import vip.xiaonuo.auth.api.SaBaseLoginUserApi;
import vip.xiaonuo.auth.core.enums.SaClientTypeEnum;
import vip.xiaonuo.auth.core.pojo.SaBaseClientLoginUser;
import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
import vip.xiaonuo.auth.core.util.AuthEmailFormatUtl;
import vip.xiaonuo.auth.core.util.StpClientLoginUserUtil;
import vip.xiaonuo.auth.core.util.StpClientUtil;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.auth.modular.login.enums.AuthDeviceTypeEnum;
import vip.xiaonuo.auth.modular.login.enums.AuthExceptionEnum;
import vip.xiaonuo.auth.modular.login.param.AuthAccountPasswordLoginParam;
import vip.xiaonuo.auth.modular.login.param.AuthGetPhoneValidCodeParam;
import vip.xiaonuo.auth.modular.login.param.AuthPhoneValidCodeLoginParam;
import vip.xiaonuo.auth.modular.login.enums.AuthPhoneOrEmailTypeEnum;
import vip.xiaonuo.auth.modular.login.enums.AuthStrategyWhenNoUserWithPhoneOrEmailEnum;
import vip.xiaonuo.auth.modular.login.param.*;
import vip.xiaonuo.auth.modular.login.result.AuthPicValidCodeResult;
import vip.xiaonuo.auth.modular.login.service.AuthService;
import vip.xiaonuo.common.cache.CommonCacheOperator;
@ -45,7 +47,9 @@ import vip.xiaonuo.common.consts.CacheConstant;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.util.CommonCryptogramUtil;
import vip.xiaonuo.common.util.CommonEmailUtil;
import vip.xiaonuo.common.util.CommonTimeFormatUtil;
import vip.xiaonuo.dev.api.DevConfigApi;
import vip.xiaonuo.dev.api.DevEmailApi;
import vip.xiaonuo.dev.api.DevSmsApi;
import java.util.List;
@ -60,10 +64,82 @@ import java.util.stream.Collectors;
@Service
public class AuthServiceImpl implements AuthService {
private static final String SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_KEY = "SNOWY_SYS_DEFAULT_CAPTCHA_OPEN";
/** B端验证码是否开启适用图片验证码 */
private static final String SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_FLAG_FOR_B_KEY = "SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_FLAG_FOR_B";
/** C端验证码是否开启适用图片验证码 */
private static final String SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_FLAG_FOR_C_KEY = "SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_FLAG_FOR_C";
/** B端验证码失效时间适用图片验证码和短信验证码单位分钟默认5分钟有效 */
private static final String SNOWY_SYS_DEFAULT_CAPTCHA_EXPIRED_DURATION_FOR_B_KEY = "SNOWY_SYS_DEFAULT_CAPTCHA_EXPIRED_DURATION_FOR_B";
/** C端验证码失效时间适用图片验证码和短信验证码单位分钟默认5分钟有效 */
private static final String SNOWY_SYS_DEFAULT_CAPTCHA_EXPIRED_DURATION_FOR_C_KEY = "SNOWY_SYS_DEFAULT_CAPTCHA_EXPIRED_DURATION_FOR_C";
/** B端登录验证码短信消息模板编码 */
private static final String SNOWY_SMS_TEMPLATE_VALID_CODE_LOGIN_FOR_B_KEY = "SNOWY_SMS_TEMPLATE_VALID_CODE_LOGIN_FOR_B";
/** C端登录验证码短信消息模板编码 */
private static final String SNOWY_SMS_TEMPLATE_VALID_CODE_LOGIN_FOR_C_KEY = "SNOWY_SMS_TEMPLATE_VALID_CODE_LOGIN_FOR_C";
/** B端登录验证码邮件消息模板内容 */
private static final String SNOWY_EMAIL_TEMPLATE_VALID_CODE_LOGIN_FOR_B_KEY = "SNOWY_EMAIL_TEMPLATE_VALID_CODE_LOGIN_FOR_B";
/** C端登录验证码邮件消息模板内容 */
private static final String SNOWY_EMAIL_TEMPLATE_VALID_CODE_LOGIN_FOR_C_KEY = "SNOWY_EMAIL_TEMPLATE_VALID_CODE_LOGIN_FOR_C";
/** B端连续登录失败持续时间即N分钟内连续登录失败单位分钟 */
private static final String SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_DURATION_FOR_B_KEY = "SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_DURATION_FOR_B";
/** C端连续登录失败持续时间即N分钟内连续登录失败单位分钟 */
private static final String SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_DURATION_FOR_C_KEY = "SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_DURATION_FOR_C";
/** B端连续登录失败次数即指定分钟内连续登录失败N次 */
private static final String SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_TIMES_FOR_B_KEY = "SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_TIMES_FOR_B";
/** C端连续登录失败次数即指定分钟内连续登录失败N次 */
private static final String SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_TIMES_FOR_C_KEY = "SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_TIMES_FOR_C";
/** B端连续登录失败锁定时间即指定分钟内连续登录失败指定次数锁定N分钟单位分钟 */
private static final String SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_LOCK_DURATION_FOR_B_KEY = "SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_LOCK_DURATION_FOR_B";
/** C端连续登录失败锁定时间即指定分钟内连续登录失败指定次数锁定N分钟单位分钟 */
private static final String SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_LOCK_DURATION_FOR_C_KEY = "SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_LOCK_DURATION_FOR_C";
/** B端手机号登录是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_B_KEY = "SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_B";
/** C端手机号登录是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_C_KEY = "SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_C";
/** B端邮箱登录是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_B_KEY = "SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_B";
/** C端邮箱登录是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_C_KEY = "SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_C";
/** B端手机号无对应用户时策略 */
private static final String SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_PHONE_FOR_B_KEY = "SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_PHONE_FOR_B";
/** C端手机号无对应用户时策略 */
private static final String SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_PHONE_FOR_C_KEY = "SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_PHONE_FOR_C";
/** B端邮箱无对应用户时策略 */
private static final String SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_EMAIL_FOR_B_KEY = "SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_EMAIL_FOR_B";
/** C端邮箱无对应用户时策略 */
private static final String SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_EMAIL_FOR_C_KEY = "SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_EMAIL_FOR_C";
/** B端注册是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_B_KEY = "SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_B";
/** C端注册是否开启 */
private static final String SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_C_KEY = "SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_C";
/** 验证码缓存前缀 */
private static final String AUTH_VALID_CODE_CACHE_KEY = "auth-validCode:";
/** 失败次数缓存前缀 */
private static final String LOGIN_ERROR_TIMES_KEY_PREFIX = "login-error-times:";
@Resource(name = "loginUserApi")
@ -78,6 +154,9 @@ public class AuthServiceImpl implements AuthService {
@Resource
private DevSmsApi devSmsApi;
@Resource
private DevEmailApi devEmailApi;
@Resource
private CommonCacheOperator commonCacheOperator;
@ -97,13 +176,17 @@ public class AuthServiceImpl implements AuthService {
authPicValidCodeResult.setValidCodeBase64(validCodeBase64);
// 将请求号返回前端
authPicValidCodeResult.setValidCodeReqNo(validCodeReqNo);
// 将请求号作为key验证码的值作为value放到redis用于校验5分钟有效
commonCacheOperator.put(AUTH_VALID_CODE_CACHE_KEY + validCodeReqNo, validCode, 5 * 60);
// 获取验证码失效时间(单位:秒)
long validCodeExpiredDuration = this.getValidCodeExpiredDuration(type);
// 将请求号作为key验证码的值作为value放到redis用于校验
commonCacheOperator.put(AUTH_VALID_CODE_CACHE_KEY + validCodeReqNo, validCode, validCodeExpiredDuration);
return authPicValidCodeResult;
}
@Override
public String getPhoneValidCode(AuthGetPhoneValidCodeParam authGetPhoneValidCodeParam, String type) {
// 校验是否允许手机号登录
this.checkAllowPhoneLoginFlag(type);
// 手机号
String phone = authGetPhoneValidCodeParam.getPhone();
// 验证码
@ -111,26 +194,123 @@ public class AuthServiceImpl implements AuthService {
// 验证码请求号
String validCodeReqNo = authGetPhoneValidCodeParam.getValidCodeReqNo();
// 校验参数
validPhoneValidCodeParam(null, validCode, validCodeReqNo, type);
validPhoneOrEmailValidCodeParam(null, AuthPhoneOrEmailTypeEnum.PHONE.getValue(), validCode, validCodeReqNo, type);
// 生成手机验证码的值随机6为数字
String phoneValidCode = RandomUtil.randomNumbers(6);
// 生成手机验证码的请求号
String phoneValidCodeReqNo = IdWorker.getIdStr();
// TODO 使用阿里云执行发送验证码,将验证码作为短信内容的参数变量放入,
// TODO 签名不传则使用系统默认配置的签名,支持传入多个参数,示例:{"name":"张三","number":"15038****76"}
//devSmsApi.sendSmsAliyun(phone, null, "验证码模板号", JSONUtil.toJsonStr(JSONUtil.createObj().set("validCode", phoneValidCode)));
// TODO 使用腾讯云执行发送验证码,将验证码作为短信内容的参数变量放入,
// TODO sdkAppId和签名不传则使用系统默认配置的sdkAppId和签名支持传入多个参数逗号拼接示例"张三,15038****76,进行中"
devSmsApi.sendSmsTencent("sdkAppId", phone, "签名", "模板编码", phoneValidCode);
// 将请求号作为key验证码的值作为value放到redis用于校验5分钟有效
commonCacheOperator.put(AUTH_VALID_CODE_CACHE_KEY + phone + StrUtil.UNDERLINE + phoneValidCodeReqNo, phoneValidCode, 5 * 60);
// 登录验证码短信消息模板编码
String smsTemplateCode;
if(SaClientTypeEnum.B.getValue().equals(type)) {
smsTemplateCode = devConfigApi.getValueByKey(SNOWY_SMS_TEMPLATE_VALID_CODE_LOGIN_FOR_B_KEY);
} else {
smsTemplateCode = devConfigApi.getValueByKey(SNOWY_SMS_TEMPLATE_VALID_CODE_LOGIN_FOR_C_KEY);
}
if(ObjectUtil.isEmpty(smsTemplateCode)){
throw new CommonException("请联系管理员配置{}端登录验证码短信消息模板编码", type);
}
// 获取验证码失效时间(单位:秒)
long validCodeExpiredDuration = this.getValidCodeExpiredDuration(type);
// 模板内容转为JSONObject
JSONObject contentJSONObject = JSONUtil.parseObj(smsTemplateCode);
// 定义变量参数
JSONObject paramMap = JSONUtil.createObj().set("userPhone", phone).set("validCode", phoneValidCode).set("validTime", validCodeExpiredDuration/60);
// 获取编码
String codeValue = contentJSONObject.getStr("code");
// 发送短信
devSmsApi.sendDynamicSms(phone, codeValue, paramMap);
// 将请求号作为key验证码的值作为value放到redis用于校验
commonCacheOperator.put(AUTH_VALID_CODE_CACHE_KEY + phone + StrUtil.UNDERLINE + phoneValidCodeReqNo, phoneValidCode, validCodeExpiredDuration);
// 返回请求号
return phoneValidCodeReqNo;
}
/**
*
*
* @author xuyuxiang
* @date 2022/8/25 15:16
**/
private void checkAllowPhoneLoginFlag(String type) {
// 是否允许手机号登录
String allowPhoneLoginFlag;
if(SaClientTypeEnum.B.getValue().equals(type)) {
allowPhoneLoginFlag = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_B_KEY);
} else {
allowPhoneLoginFlag = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_C_KEY);
}
if(ObjectUtil.isNotEmpty(allowPhoneLoginFlag)) {
if(!Convert.toBool(allowPhoneLoginFlag)) {
throw new CommonException("管理员未开启手机号登录");
}
}
}
@Override
public String getEmailValidCode(AuthGetEmailValidCodeParam authGetEmailValidCodeParam, String type) {
// 校验是否允许邮箱登录
this.checkAllowEmailLoginFlag(type);
// 邮箱 */
String email = authGetEmailValidCodeParam.getEmail();
// 验证码
String validCode = authGetEmailValidCodeParam.getValidCode();
// 验证码请求号
String validCodeReqNo = authGetEmailValidCodeParam.getValidCodeReqNo();
// 校验参数
validPhoneOrEmailValidCodeParam(null, AuthPhoneOrEmailTypeEnum.EMAIL.getValue(), validCode, validCodeReqNo, type);
// 生成邮箱验证码的值随机6为数字
String emailValidCode = RandomUtil.randomNumbers(6);
// 生成邮箱验证码的请求号
String emailValidCodeReqNo = IdWorker.getIdStr();
// 登录验证码邮件消息模板内容
String emailTemplateContent;
if(SaClientTypeEnum.B.getValue().equals(type)) {
emailTemplateContent = devConfigApi.getValueByKey(SNOWY_EMAIL_TEMPLATE_VALID_CODE_LOGIN_FOR_B_KEY);
} else {
emailTemplateContent = devConfigApi.getValueByKey(SNOWY_EMAIL_TEMPLATE_VALID_CODE_LOGIN_FOR_C_KEY);
}
if(ObjectUtil.isEmpty(emailTemplateContent)){
throw new CommonException("请联系管理员配置{}端登录验证码邮件消息模板内容", type);
}
// 获取验证码失效时间(单位:秒)
long validCodeExpiredDuration = this.getValidCodeExpiredDuration(type);
// 模板内容转为JSONObject
JSONObject contentJSONObject = JSONUtil.parseObj(emailTemplateContent);
// 定义变量参数
JSONObject paramMap = JSONUtil.createObj().set("userEmail", email).set("validCode", emailValidCode).set("validTime", validCodeExpiredDuration/60);
// 获取格式化后的主题
String subject = AuthEmailFormatUtl.format(contentJSONObject.getStr("subject"), paramMap);;
// 获取格式化后的内容
String content = AuthEmailFormatUtl.format(contentJSONObject.getStr("content"), paramMap);;
// 发送邮件
devEmailApi.sendDynamicHtmlEmail(email, subject, content);
// 将请求号作为key验证码的值作为value放到redis用于校验
commonCacheOperator.put(AUTH_VALID_CODE_CACHE_KEY + email + StrUtil.UNDERLINE + emailValidCodeReqNo, emailValidCode, validCodeExpiredDuration);
// 返回请求号
return emailValidCodeReqNo;
}
/**
*
*
* @author xuyuxiang
* @date 2022/8/25 15:16
**/
private void checkAllowEmailLoginFlag(String type) {
// 是否允许邮箱登录
String allowEmailLoginFlag;
if(SaClientTypeEnum.B.getValue().equals(type)) {
allowEmailLoginFlag = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_B_KEY);
} else {
allowEmailLoginFlag = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_C_KEY);
}
if(ObjectUtil.isNotEmpty(allowEmailLoginFlag)) {
if(!Convert.toBool(allowEmailLoginFlag)) {
throw new CommonException("管理员未开启邮箱登录");
}
}
}
/**
*
*
@ -141,8 +321,10 @@ public class AuthServiceImpl implements AuthService {
// 依据请求号,取出缓存中的验证码进行校验
Object existValidCode;
if(ObjectUtil.isEmpty(phoneOrEmail)) {
// 图形验证码
existValidCode = commonCacheOperator.get(AUTH_VALID_CODE_CACHE_KEY + validCodeReqNo);
} else {
// 手机或者邮箱验证码
existValidCode = commonCacheOperator.get(AUTH_VALID_CODE_CACHE_KEY + phoneOrEmail + StrUtil.UNDERLINE + validCodeReqNo);
}
// 为空则直接验证码错误
@ -151,8 +333,10 @@ public class AuthServiceImpl implements AuthService {
}
// 移除该验证码
if(ObjectUtil.isEmpty(phoneOrEmail)) {
// 图形验证码
commonCacheOperator.remove(AUTH_VALID_CODE_CACHE_KEY + validCodeReqNo);
} else {
// 手机或者邮箱验证码
commonCacheOperator.remove(AUTH_VALID_CODE_CACHE_KEY + phoneOrEmail + StrUtil.UNDERLINE + validCodeReqNo);
}
// 不一致则直接验证码错误
@ -167,28 +351,59 @@ public class AuthServiceImpl implements AuthService {
* @author xuyuxiang
* @date 2022/8/25 14:29
**/
private void validPhoneValidCodeParam(String phoneOrEmail, String validCode, String validCodeReqNo, String type) {
private String validPhoneOrEmailValidCodeParam(String phoneOrEmail, String phoneOrEmailType, String validCode,
String validCodeReqNo, String type) {
// 验证码正确则校验手机号格式
if(ObjectUtil.isEmpty(phoneOrEmail)) {
// 执行校验验证码
validValidCode(null, validCode, validCodeReqNo);
} else {
if(!PhoneUtil.isMobile(phoneOrEmail) && !CommonEmailUtil.isEmail(phoneOrEmail)) {
throw new CommonException(AuthExceptionEnum.PHONE_FORMAT_ERROR.getValue());
}
// 执行校验验证码
validValidCode(phoneOrEmail, validCode, validCodeReqNo);
// 根据手机号获取用户信息判断用户是否存在根据B端或C端判断
// 根据手机号或者邮箱获取用户信息判断用户是否存在根据B端或C端判断
if(SaClientTypeEnum.B.getValue().equals(type)) {
if(ObjectUtil.isEmpty(loginUserApi.getUserByPhone(phoneOrEmail))) {
throw new CommonException(AuthExceptionEnum.PHONE_ERROR.getValue());
if(phoneOrEmailType.equals(AuthPhoneOrEmailTypeEnum.PHONE.getValue())) {
SaBaseLoginUser saBaseLoginUser = loginUserApi.getUserByPhone(phoneOrEmail);
if(ObjectUtil.isEmpty(saBaseLoginUser)) {
// B端手机号无对应用户时策略
return devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_PHONE_FOR_B_KEY);
}
} else {
SaBaseLoginUser saBaseLoginUser = loginUserApi.getUserByEmail(phoneOrEmail);
if(ObjectUtil.isEmpty(saBaseLoginUser)) {
// B端邮箱无对应用户时策略
return devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_EMAIL_FOR_B_KEY);
}
}
} else {
if(ObjectUtil.isEmpty(clientLoginUserApi.getClientUserByPhone(phoneOrEmail))) {
throw new CommonException(AuthExceptionEnum.PHONE_ERROR.getValue());
if(phoneOrEmailType.equals(AuthPhoneOrEmailTypeEnum.PHONE.getValue())) {
SaBaseClientLoginUser saBaseClientLoginUser = clientLoginUserApi.getClientUserByPhone(phoneOrEmail);
if(ObjectUtil.isEmpty(saBaseClientLoginUser)) {
// C端手机号无对应用户时策略
return devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_PHONE_FOR_C_KEY);
}
} else {
SaBaseClientLoginUser saBaseClientLoginUser = clientLoginUserApi.getClientUserByEmail(phoneOrEmail);
if(ObjectUtil.isEmpty(saBaseClientLoginUser)) {
// BC端邮箱无对应用户时策略
return devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_STRATEGY_WHEN_NO_USER_WITH_EMAIL_FOR_C_KEY);
}
}
}
// 执行校验图形验证码
validValidCode(null, validCode, validCodeReqNo);
// 返回空值
return null;
} else {
AuthPhoneOrEmailTypeEnum.validate(phoneOrEmailType);
if(phoneOrEmailType.equals(AuthPhoneOrEmailTypeEnum.PHONE.getValue())) {
if(!PhoneUtil.isMobile(phoneOrEmail)) {
throw new CommonException(AuthExceptionEnum.PHONE_FORMAT_ERROR.getValue());
}
} else {
if(CommonEmailUtil.isNotEmail(phoneOrEmail)) {
throw new CommonException(AuthExceptionEnum.PHONE_FORMAT_ERROR.getValue());
}
}
// 执行校验手机或者邮箱验证码
validValidCode(phoneOrEmail, validCode, validCodeReqNo);
// 返回空值
return null;
}
}
@ -209,7 +424,12 @@ public class AuthServiceImpl implements AuthService {
AuthDeviceTypeEnum.validate(device);
}
// 校验验证码
String defaultCaptchaOpen = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_KEY);
String defaultCaptchaOpen;
if(SaClientTypeEnum.B.getValue().equals(type)) {
defaultCaptchaOpen = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_FLAG_FOR_B_KEY);
} else {
defaultCaptchaOpen = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_FLAG_FOR_C_KEY);
}
if(ObjectUtil.isNotEmpty(defaultCaptchaOpen)) {
if(Convert.toBool(defaultCaptchaOpen)) {
// 获取验证码
@ -224,7 +444,7 @@ public class AuthServiceImpl implements AuthService {
if(ObjectUtil.isEmpty(validCodeReqNo)) {
throw new CommonException(AuthExceptionEnum.VALID_CODE_REQ_NO_EMPTY.getValue());
}
// 执行校验验证码
// 执行校验图形验证码
validValidCode(null, validCode, validCodeReqNo);
}
}
@ -240,24 +460,24 @@ public class AuthServiceImpl implements AuthService {
if(SaClientTypeEnum.B.getValue().equals(type)) {
SaBaseLoginUser saBaseLoginUser = loginUserApi.getUserByAccount(account);
if(ObjectUtil.isEmpty(saBaseLoginUser)) {
// 提示账号错误
throw new CommonException(AuthExceptionEnum.ACCOUNT_ERROR.getValue());
}
if (!saBaseLoginUser.getPassword().equals(passwordHash)) {
// 记录登录次数 和 过期时间
saveLoginTimes(account);
throw new CommonException(AuthExceptionEnum.PWD_ERROR.getValue());
// 密码错误,处理剩余次数提示信息
handleRemainingTimes(account, AuthExceptionEnum.PWD_ERROR.getValue(), type);
}
// 删除redis 中的key
clearLoginErrorTimes(account);
// 执行B端登录
return execLoginB(saBaseLoginUser, device);
} else {
SaBaseClientLoginUser saBaseClientLoginUser = clientLoginUserApi.getClientUserByAccount(account);
if(ObjectUtil.isEmpty(saBaseClientLoginUser)) {
// 提示账号错误
throw new CommonException(AuthExceptionEnum.ACCOUNT_ERROR.getValue());
}
if (!saBaseClientLoginUser.getPassword().equals(passwordHash)) {
throw new CommonException(AuthExceptionEnum.PWD_ERROR.getValue());
// 密码错误,处理剩余次数提示信息
handleRemainingTimes(account, AuthExceptionEnum.PWD_ERROR.getValue(), type);
}
// 执行C端登录
return execLoginC(saBaseClientLoginUser, device);
@ -266,10 +486,14 @@ public class AuthServiceImpl implements AuthService {
@Override
public String doLoginByPhone(AuthPhoneValidCodeLoginParam authPhoneValidCodeLoginParam, String type) {
// 校验是否允许手机号登录
this.checkAllowPhoneLoginFlag(type);
// 手机号
String phone = authPhoneValidCodeLoginParam.getPhone();
// 校验参数
validPhoneValidCodeParam(phone, authPhoneValidCodeLoginParam.getValidCode(), authPhoneValidCodeLoginParam.getValidCodeReqNo(), type);
// 校验参数,返回手机号无对应用户时的策略
String strategyWhenNoUserWithPhoneOrEmail = validPhoneOrEmailValidCodeParam(phone,
AuthPhoneOrEmailTypeEnum.PHONE.getValue(), authPhoneValidCodeLoginParam.getValidCode(),
authPhoneValidCodeLoginParam.getValidCodeReqNo(), type);
// 设备
String device = authPhoneValidCodeLoginParam.getDevice();
// 默认指定为PC如在小程序跟移动端的情况下自行指定即可
@ -282,20 +506,115 @@ public class AuthServiceImpl implements AuthService {
if(SaClientTypeEnum.B.getValue().equals(type)) {
SaBaseLoginUser saBaseLoginUser = loginUserApi.getUserByPhone(phone);
if(ObjectUtil.isEmpty(saBaseLoginUser)) {
throw new CommonException(AuthExceptionEnum.ACCOUNT_ERROR.getValue());
// 判断手机号无对应用户时的策略,如果为空则直接抛出异常
if(ObjectUtil.isEmpty(strategyWhenNoUserWithPhoneOrEmail)) {
throw new CommonException("手机号码:{}不存在对应用户", phone);
} else {
// 如果不允许登录,则抛出异常
if(AuthStrategyWhenNoUserWithPhoneOrEmailEnum.NOT_ALLOW_LOGIN.getValue().equals(strategyWhenNoUserWithPhoneOrEmail)) {
throw new CommonException("手机号码:{}不存在对应用户", phone);
} else {
// 根据手机号自动创建B端用户
saBaseLoginUser = loginUserApi.createUserWithPhone(phone);
}
}
}
// 执行B端登录
return execLoginB(saBaseLoginUser, device);
} else {
SaBaseClientLoginUser saBaseClientLoginUser = clientLoginUserApi.getClientUserByPhone(phone);
if(ObjectUtil.isEmpty(saBaseClientLoginUser)) {
throw new CommonException(AuthExceptionEnum.ACCOUNT_ERROR.getValue());
// 判断手机号无对应用户时的策略,如果为空则直接抛出异常
if(ObjectUtil.isEmpty(strategyWhenNoUserWithPhoneOrEmail)) {
throw new CommonException("手机号码:{}不存在对应用户", phone);
} else {
// 如果不允许登录,则抛出异常
if(AuthStrategyWhenNoUserWithPhoneOrEmailEnum.NOT_ALLOW_LOGIN.getValue().equals(strategyWhenNoUserWithPhoneOrEmail)) {
throw new CommonException("手机号码:{}不存在对应用户", phone);
} else {
// 根据手机号自动创建C端用户
saBaseClientLoginUser = clientLoginUserApi.createClientUserWithPhone(phone);
}
}
}
// 执行C端登录
return execLoginC(saBaseClientLoginUser, device);
}
}
@Override
public String doLoginByEmail(AuthEmailValidCodeLoginParam authEmailValidCodeLoginParam, String type) {
// 校验是否允许邮箱登录
this.checkAllowEmailLoginFlag(type);
// 邮箱
String email = authEmailValidCodeLoginParam.getEmail();
// 校验参数,返回邮箱无对应用户时的策略
String strategyWhenNoUserWithPhoneOrEmail = validPhoneOrEmailValidCodeParam(email,
AuthPhoneOrEmailTypeEnum.EMAIL.getValue(), authEmailValidCodeLoginParam.getValidCode(),
authEmailValidCodeLoginParam.getValidCodeReqNo(), type);
// 设备
String device = authEmailValidCodeLoginParam.getDevice();
// 默认指定为PC如在小程序跟移动端的情况下自行指定即可
if(ObjectUtil.isEmpty(device)) {
device = AuthDeviceTypeEnum.PC.getValue();
} else {
AuthDeviceTypeEnum.validate(device);
}
// 根据邮箱获取用户信息根据B端或C端判断
if(SaClientTypeEnum.B.getValue().equals(type)) {
SaBaseLoginUser saBaseLoginUser = loginUserApi.getUserByEmail(email);
if(ObjectUtil.isEmpty(saBaseLoginUser)) {
// 判断邮箱无对应用户时的策略,如果为空则直接抛出异常
if(ObjectUtil.isEmpty(strategyWhenNoUserWithPhoneOrEmail)) {
throw new CommonException("邮箱:{}不存在对应用户", email);
} else {
// 如果不允许登录,则抛出异常
if(AuthStrategyWhenNoUserWithPhoneOrEmailEnum.NOT_ALLOW_LOGIN.getValue().equals(strategyWhenNoUserWithPhoneOrEmail)) {
throw new CommonException("邮箱:{}不存在对应用户", email);
} else {
// 根据邮箱自动创建B端用户
saBaseLoginUser = loginUserApi.createUserWithEmail(email);
}
}
}
// 执行B端登录
return execLoginB(saBaseLoginUser, device);
} else {
SaBaseClientLoginUser saBaseClientLoginUser = clientLoginUserApi.getClientUserByEmail(email);
if(ObjectUtil.isEmpty(saBaseClientLoginUser)) {
// 判断邮箱无对应用户时的策略,如果为空则直接抛出异常
if(ObjectUtil.isEmpty(strategyWhenNoUserWithPhoneOrEmail)) {
throw new CommonException("邮箱:{}不存在对应用户", email);
} else {
// 如果不允许登录,则抛出异常
if(AuthStrategyWhenNoUserWithPhoneOrEmailEnum.NOT_ALLOW_LOGIN.getValue().equals(strategyWhenNoUserWithPhoneOrEmail)) {
throw new CommonException("邮箱:{}不存在对应用户", email);
} else {
// 根据邮箱自动创建C端用户
saBaseClientLoginUser = clientLoginUserApi.createClientUserWithEmail(email);
}
}
}
// 执行C端登录
return execLoginC(saBaseClientLoginUser, device);
}
}
/**
*
*/
private void handleRemainingTimes(String account, String errorMessage, String type) {
// 记录登录次数 和 过期时间
int remainingTimes = saveLoginTimes(account, type);
if(remainingTimes == 0) {
// 此时已封禁,返回提示语
isDisableTime(account);
} else {
// 提示错误
throw new CommonException(errorMessage + ",您还可以尝试【" + remainingTimes + "】次");
}
}
/**
*
*
@ -304,33 +623,81 @@ public class AuthServiceImpl implements AuthService {
// disableTime = -2表示未被封禁
long disableTime = StpUtil.getDisableTime(userAccount);
if (disableTime > 0) {
if (disableTime > 60) {
throw new CommonException(userAccount + "账号已被封禁, 请再"+ disableTime/60+ "分钟后重新尝试登录!!");
}
throw new CommonException(userAccount + "账号已被封禁, 请再"+ disableTime+ "秒后重新尝试登录!!");
String formatTime = CommonTimeFormatUtil.formatSeconds(disableTime);
throw new CommonException("账号" + userAccount + "已被封禁, 请在"+ formatTime+ "后重新尝试登录!");
}
}
// redis中保存登录错误次数
private void saveLoginTimes(String userAccount){
String loginErrorKey = LOGIN_ERROR_TIMES_KEY_PREFIX + userAccount;
/**
* redis
*/
private int saveLoginTimes(String userAccount, String type){
// 获取连续登录失败持续时间
String configContinuousLoginFailDuration;
// 获取连续登录失败次数
String configContinuousLoginFailTimes;
// 获取连续登录失败锁定时间
String configContinuousLoginFailLockDuration;
if(SaClientTypeEnum.B.getValue().equals(type)) {
configContinuousLoginFailDuration = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_DURATION_FOR_B_KEY);
configContinuousLoginFailTimes = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_TIMES_FOR_B_KEY);
configContinuousLoginFailLockDuration = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_LOCK_DURATION_FOR_B_KEY);
} else {
configContinuousLoginFailDuration = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_DURATION_FOR_C_KEY);
configContinuousLoginFailTimes = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_TIMES_FOR_C_KEY);
configContinuousLoginFailLockDuration = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CONTINUOUS_LOGIN_FAIL_LOCK_DURATION_FOR_C_KEY);
}
// 连续登录失败持续时间默认5分钟
long continuousLoginFailDuration = 5 * 60;
if(ObjectUtil.isNotEmpty(configContinuousLoginFailDuration)){
// 配置了则使用配置的失效时间
continuousLoginFailDuration = Convert.toLong(configContinuousLoginFailDuration) * 60;
}
// 连续登录失败次数默认5次
int continuousLoginFailTimes = 5;
if(ObjectUtil.isNotEmpty(configContinuousLoginFailTimes)){
// 配置了则使用配置的失效时间
continuousLoginFailTimes = Convert.toInt(configContinuousLoginFailTimes);
}
// 连续登录失败锁定时间默认5分钟
long continuousLoginFailLockDuration = 5 * 60;
if(ObjectUtil.isNotEmpty(configContinuousLoginFailLockDuration)){
// 配置了则使用配置的失效时间
continuousLoginFailLockDuration = Convert.toLong(configContinuousLoginFailLockDuration) * 60;
}
// 获取登录失败次数缓存键
String loginErrorKey = LOGIN_ERROR_TIMES_KEY_PREFIX + ":" + userAccount;
// 获取登录失败次数缓存值
Integer number = (Integer) commonCacheOperator.get(loginErrorKey);
if (number == null) {
// 如果redis中没有保存代表失败第一次
number = 2;
commonCacheOperator.put(loginErrorKey, number,5 * 60);
return;
// 如果redis中没有保存代表失败第一次如果配置的值为1次
if(continuousLoginFailTimes == 1) {
// 直接进入isDisableTime方法返回用户还需等待时间
StpUtil.disable(userAccount, continuousLoginFailLockDuration);
// 删除redis 中的key
clearLoginErrorTimes(userAccount);
return 0;
} else {
// 否则失败次数为2
number = 2;
commonCacheOperator.put(loginErrorKey, number, continuousLoginFailDuration);
return continuousLoginFailTimes - number + 1;
}
} else {
if (number < continuousLoginFailTimes) {
number++;
commonCacheOperator.put(loginErrorKey, number, continuousLoginFailDuration);
return continuousLoginFailTimes - number + 1;
} else {
// 第N次封禁账号第N+1次进入isDisableTime方法返回用户还需等待时间
StpUtil.disable(userAccount, continuousLoginFailLockDuration);
// 删除redis 中的key
clearLoginErrorTimes(userAccount);
return 0;
}
}
if (number < 5) {
number++;
commonCacheOperator.put(loginErrorKey, number,5 * 60);
return;
}
// 第五次封禁账号,第六次进入isDisableTime方法返回用户还需等待时间
StpUtil.disable(userAccount, 5 * 60);
// 删除redis 中的key
clearLoginErrorTimes(userAccount);
}
/**
@ -338,7 +705,8 @@ public class AuthServiceImpl implements AuthService {
* @param userAccount
*/
private void clearLoginErrorTimes(String userAccount) {
String loginErrorKey = LOGIN_ERROR_TIMES_KEY_PREFIX + userAccount;
// 获取登录失败次数缓存键
String loginErrorKey = LOGIN_ERROR_TIMES_KEY_PREFIX + ":" + userAccount;
// 删除redis中的key
commonCacheOperator.remove(loginErrorKey);
}
@ -466,11 +834,11 @@ public class AuthServiceImpl implements AuthService {
// 填充B端用户信息并更新缓存
fillSaBaseLoginUserAndUpdateCache(saBaseLoginUser);
// 去掉密码
saBaseLoginUser.setPassword(null);
saBaseLoginUser.setPassword("******");
// 去掉权限码
saBaseLoginUser.setPermissionCodeList(null);
saBaseLoginUser.setPermissionCodeList(CollectionUtil.newArrayList());
// 去掉数据范围
saBaseLoginUser.setDataScopeList(null);
saBaseLoginUser.setDataScopeList(CollectionUtil.newArrayList());
// 返回
return saBaseLoginUser;
}
@ -490,11 +858,11 @@ public class AuthServiceImpl implements AuthService {
// 填充C端用户信息并更新缓存
fillSaBaseClientLoginUserAndUpdateCache(saBaseClientLoginUser);
// 去掉密码
saBaseClientLoginUser.setPassword(null);
saBaseClientLoginUser.setPassword("******");
// 去掉权限码
saBaseClientLoginUser.setPermissionCodeList(null);
saBaseClientLoginUser.setPermissionCodeList(CollectionUtil.newArrayList());
// 去掉数据范围
saBaseClientLoginUser.setDataScopeList(null);
saBaseClientLoginUser.setDataScopeList(CollectionUtil.newArrayList());
// 返回
return saBaseClientLoginUser;
}
@ -518,4 +886,93 @@ public class AuthServiceImpl implements AuthService {
return execLoginC(saBaseClientLoginUser, device);
}
}
@Override
public void register(AuthRegisterParam authRegisterParam, String type) {
// 校验是否允许注册
this.checkAllowRegisterFlag(type);
// 获取账号
String account = authRegisterParam.getAccount();
// 获取密码
String password = authRegisterParam.getPassword();
// 校验验证码
String defaultCaptchaOpen;
if(SaClientTypeEnum.B.getValue().equals(type)) {
defaultCaptchaOpen = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_FLAG_FOR_B_KEY);
} else {
defaultCaptchaOpen = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_FLAG_FOR_C_KEY);
}
if(ObjectUtil.isNotEmpty(defaultCaptchaOpen)) {
if(Convert.toBool(defaultCaptchaOpen)) {
// 获取验证码
String validCode = authRegisterParam.getValidCode();
// 获取验证码请求号
String validCodeReqNo = authRegisterParam.getValidCodeReqNo();
// 开启验证码则必须传入验证码
if(ObjectUtil.isEmpty(validCode)) {
throw new CommonException(AuthExceptionEnum.VALID_CODE_EMPTY.getValue());
}
// 开启验证码则必须传入验证码请求号
if(ObjectUtil.isEmpty(validCodeReqNo)) {
throw new CommonException(AuthExceptionEnum.VALID_CODE_REQ_NO_EMPTY.getValue());
}
// 执行校验图形验证码
validValidCode(null, validCode, validCodeReqNo);
}
}
// SM2解密前端传来的密码
String passwordDecrypt = CommonCryptogramUtil.doSm2Decrypt(password);
// 根据账号获取用户信息根据B端或C端判断
if(SaClientTypeEnum.B.getValue().equals(type)) {
clientLoginUserApi.doRegister(account, passwordDecrypt);
} else {
loginUserApi.doRegister(account, passwordDecrypt);
}
}
/**
*
*
* @author xuyuxiang
* @date 2022/8/25 15:16
**/
private void checkAllowRegisterFlag(String type) {
// 是否允许注册
String allowRegisterFlag;
if(SaClientTypeEnum.B.getValue().equals(type)) {
allowRegisterFlag = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_B_KEY);
} else {
allowRegisterFlag = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_C_KEY);
}
if(ObjectUtil.isNotEmpty(allowRegisterFlag)) {
if(!Convert.toBool(allowRegisterFlag)) {
throw new CommonException("管理员未开启注册");
}
}
}
/**
*
*
* @author xuyuxiang
* @date 2025/3/21 20:25
**/
private long getValidCodeExpiredDuration(String type) {
// 默认5分钟
int defaultExpiredTime = 5;
// 获取配置验证码失效时间(单位:分钟)
String configCaptchaExpiredDuration;
if(SaClientTypeEnum.B.getValue().equals(type)) {
configCaptchaExpiredDuration = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CAPTCHA_EXPIRED_DURATION_FOR_B_KEY);
} else {
configCaptchaExpiredDuration = devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_CAPTCHA_EXPIRED_DURATION_FOR_C_KEY);
}
// 判断是否为空
if(ObjectUtil.isNotEmpty(configCaptchaExpiredDuration)){
// 配置了则使用配置的失效时间
defaultExpiredTime = Convert.toInt(configCaptchaExpiredDuration);
}
// 转为秒
return defaultExpiredTime * 60L;
}
}

View File

@ -13,10 +13,11 @@
package vip.xiaonuo.auth.modular.monitor.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
@ -32,6 +33,7 @@ import vip.xiaonuo.auth.modular.monitor.service.AuthSessionService;
import vip.xiaonuo.common.annotation.CommonLog;
import vip.xiaonuo.common.pojo.CommonResult;
import javax.validation.Valid;
import java.util.List;
/**
@ -41,6 +43,7 @@ import java.util.List;
* @date 2022/6/24 15:20
**/
@Tag(name = "会话治理控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 3)
@RestController
@Validated
public class AuthSessionController {
@ -54,6 +57,7 @@ public class AuthSessionController {
* @author xuyuxiang
* @date 2022/6/24 22:28
*/
@ApiOperationSupport(order = 1)
@Operation(summary = "会话统计")
@GetMapping("/auth/session/analysis")
public CommonResult<AuthSessionAnalysisResult> analysis() {
@ -66,6 +70,7 @@ public class AuthSessionController {
* @author xuyuxiang
* @date 2022/6/24 22:28
*/
@ApiOperationSupport(order = 2)
@Operation(summary = "查询B端会话")
@GetMapping("/auth/session/b/page")
public CommonResult<Page<AuthSessionPageResult>> pageForB(AuthSessionPageParam authSessionPageParam) {
@ -78,6 +83,7 @@ public class AuthSessionController {
* @author xuyuxiang
* @date 2022/6/24 22:28
*/
@ApiOperationSupport(order = 3)
@Operation(summary = "查询C端会话")
@GetMapping("/auth/session/c/page")
public CommonResult<Page<AuthSessionPageResult>> pageForC(AuthSessionPageParam authSessionPageParam) {
@ -90,11 +96,12 @@ public class AuthSessionController {
* @author xuyuxiang
* @date 2021/10/12 10:25
**/
@ApiOperationSupport(order = 4)
@Operation(summary = "强退B端会话")
@CommonLog("强退B端会话")
@PostMapping("/auth/session/b/exit")
public CommonResult<String> exitSessionForB(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
List<AuthExitSessionParam> authExitSessionParamList) {
List<AuthExitSessionParam> authExitSessionParamList) {
authSessionService.exitSessionForB(authExitSessionParamList);
return CommonResult.ok();
}
@ -105,11 +112,12 @@ public class AuthSessionController {
* @author xuyuxiang
* @date 2021/10/12 10:25
**/
@ApiOperationSupport(order = 5)
@Operation(summary = "强退C端会话")
@CommonLog("强退C端会话")
@PostMapping("/auth/session/c/exit")
public CommonResult<String> exitSessionForC(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
List<AuthExitSessionParam> authExitSessionParamList) {
List<AuthExitSessionParam> authExitSessionParamList) {
authSessionService.exitSessionForC(authExitSessionParamList);
return CommonResult.ok();
}
@ -120,6 +128,7 @@ public class AuthSessionController {
* @author xuyuxiang
* @date 2021/10/12 10:25
**/
@ApiOperationSupport(order = 6)
@Operation(summary = "强退B端token")
@CommonLog("强退B端token")
@PostMapping("/auth/token/b/exit")
@ -135,6 +144,7 @@ public class AuthSessionController {
* @author xuyuxiang
* @date 2021/10/12 10:25
**/
@ApiOperationSupport(order = 7)
@Operation(summary = "强退C端token")
@CommonLog("强退C端token")
@PostMapping("/auth/token/c/exit")

View File

@ -0,0 +1,58 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.auth.modular.sso.controller;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import vip.xiaonuo.auth.core.enums.SaClientTypeEnum;
import vip.xiaonuo.auth.modular.sso.param.AuthSsoTicketLoginParam;
import vip.xiaonuo.auth.modular.sso.service.AuthSsoService;
import vip.xiaonuo.common.pojo.CommonResult;
import javax.validation.Valid;
/**
*
*
* @author xuyuxiang
* @date 2022/8/30 9:20
**/
@Tag(name = "单点登录控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 4)
@RestController
@Validated
public class AuthSsoController {
@Resource
private AuthSsoService authSsoService;
/**
* ticket
*
* @author xuyuxiang
* @date 2021/10/15 13:12
**/
@ApiOperationSupport(order = 1)
@Operation(summary = "根据ticket执行单点登录")
@PostMapping("/auth/sso/doLogin")
public CommonResult<String> doLogin(@RequestBody @Valid AuthSsoTicketLoginParam authAccountPasswordLoginParam) {
return CommonResult.data(authSsoService.doLogin(authAccountPasswordLoginParam, SaClientTypeEnum.B.getValue()));
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.auth.modular.sso.param;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
/**
* ticket
*
* @author xuyuxiang
* @date 2022/7/7 16:46
**/
@Getter
@Setter
public class AuthSsoTicketLoginParam {
/** ticket */
@Schema(description = "ticket", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "ticket不能为空")
private String ticket;
/** 设备 */
@Schema(description = "设备")
private String device;
}

View File

@ -0,0 +1,32 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.auth.modular.sso.service;
import vip.xiaonuo.auth.modular.sso.param.AuthSsoTicketLoginParam;
/**
* Service
*
* @author xuyuxiang
* @date 2022/8/30 9:20
**/
public interface AuthSsoService {
/**
* ticket
*
* @author xuyuxiang
* @date 2022/8/30 9:36
**/
String doLogin(AuthSsoTicketLoginParam authAccountPasswordLoginParam, String value);
}

View File

@ -0,0 +1,37 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.auth.modular.sso.service.impl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import vip.xiaonuo.auth.modular.login.service.AuthService;
import vip.xiaonuo.auth.modular.sso.param.AuthSsoTicketLoginParam;
import vip.xiaonuo.auth.modular.sso.service.AuthSsoService;
/**
* Service
*
* @author xuyuxiang
* @date 2022/8/30 9:21
**/
@Service
public class AuthSsoServiceImpl implements AuthSsoService {
@Resource
private AuthService authService;
@Override
public String doLogin(AuthSsoTicketLoginParam authAccountPasswordLoginParam, String device) {
return null;
}
}

View File

@ -13,10 +13,11 @@
package vip.xiaonuo.auth.modular.third.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import me.zhyd.oauth.model.AuthCallback;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
@ -29,6 +30,8 @@ import vip.xiaonuo.auth.modular.third.result.AuthThirdRenderResult;
import vip.xiaonuo.auth.modular.third.service.AuthThirdService;
import vip.xiaonuo.common.pojo.CommonResult;
import javax.validation.Valid;
/**
*
*
@ -36,6 +39,7 @@ import vip.xiaonuo.common.pojo.CommonResult;
* @date 2022/7/8 16:18
**/
@Tag(name = "三方登录控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 5)
@RestController
@Validated
public class AuthThirdController {
@ -49,6 +53,7 @@ public class AuthThirdController {
* @author xuyuxiang
* @date 2022/7/8 16:19
**/
@ApiOperationSupport(order = 1)
@Operation(summary = "第三方登录页面渲染")
@GetMapping("/auth/third/render")
public CommonResult<AuthThirdRenderResult> render(@Valid AuthThirdRenderParam authThirdRenderParam) {
@ -61,6 +66,7 @@ public class AuthThirdController {
* @author xuyuxiang
* @date 2022/7/8 16:42
**/
@ApiOperationSupport(order = 2)
@Operation(summary = "第三方登录授权回调")
@GetMapping("/auth/third/callback")
public CommonResult<String> callback(@Valid AuthThirdCallbackParam authThirdCallbackParam, AuthCallback authCallback) {
@ -73,6 +79,7 @@ public class AuthThirdController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 3)
@Operation(summary = "获取三方用户分页")
@GetMapping("/auth/third/page")
public CommonResult<Page<AuthThirdUser>> page(AuthThirdUserPageParam authThirdUserPageParam) {

View File

@ -45,7 +45,7 @@ public class AuthThirdUser extends CommonEntity {
/** 头像 */
@Schema(description = "头像")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String avatar;
/** 姓名 */
@ -54,12 +54,12 @@ public class AuthThirdUser extends CommonEntity {
/** 昵称 */
@Schema(description = "昵称")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String nickname;
/** 性别 */
@Schema(description = "性别")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String gender;
/** 分类 */
@ -68,6 +68,6 @@ public class AuthThirdUser extends CommonEntity {
/** 扩展信息 */
@Schema(description = "扩展信息")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String extJson;
}

View File

@ -39,4 +39,4 @@
<artifactId>snowy-plugin-dev-api</artifactId>
</dependency>
</dependencies>
</project>
</project>

View File

@ -23,7 +23,9 @@ import lombok.Getter;
@Getter
public enum BizBuildInEnum {
/** 超管用户账号 */
/**
*
*/
BUILD_IN_USER_ACCOUNT("superAdmin", "超管");
private final String value;

View File

@ -15,10 +15,11 @@ package vip.xiaonuo.biz.modular.dict.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@ -31,6 +32,7 @@ import vip.xiaonuo.biz.modular.dict.service.BizDictService;
import vip.xiaonuo.common.annotation.CommonLog;
import vip.xiaonuo.common.pojo.CommonResult;
import javax.validation.Valid;
import java.util.List;
/**
@ -40,6 +42,7 @@ import java.util.List;
* @date 2022/6/21 14:58
**/
@Tag(name = "业务字典控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 4)
@RestController
@Validated
public class BizDictController {
@ -53,6 +56,7 @@ public class BizDictController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 1)
@Operation(summary = "获取业务字典分页")
@SaCheckPermission("/biz/dict/page")
@GetMapping("/biz/dict/page")
@ -66,6 +70,7 @@ public class BizDictController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 2)
@Operation(summary = "获取业务字典树")
@SaCheckPermission("/biz/dict/tree")
@GetMapping("/biz/dict/tree")
@ -79,6 +84,7 @@ public class BizDictController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 3)
@Operation(summary = "获取所有字典树")
@GetMapping("/biz/dict/treeAll")
public CommonResult<List<Tree<String>>> treeAll() {
@ -91,6 +97,7 @@ public class BizDictController {
* @author xuyuxiang
* @date 2022/4/24 20:47
*/
@ApiOperationSupport(order = 4)
@Operation(summary = "编辑业务字典")
@CommonLog("编辑业务字典")
@SaCheckPermission("/biz/dict/edit")

View File

@ -57,6 +57,6 @@ public class BizDict extends CommonEntity {
/** 扩展信息 */
@Schema(description = "扩展信息")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String extJson;
}

View File

@ -29,17 +29,17 @@ import lombok.Setter;
public class BizDictEditParam {
/** id */
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "id")
@NotBlank(message = "id不能为空")
private String id;
/** 字典文字 */
@Schema(description = "字典文字", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "字典文字")
@NotBlank(message = "dictLabel不能为空")
private String dictLabel;
/** 排序码 */
@Schema(description = "排序码", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "排序码")
@NotNull(message = "sortCode不能为空")
private Integer sortCode;

View File

@ -15,23 +15,23 @@ package vip.xiaonuo.biz.modular.group.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import vip.xiaonuo.biz.modular.group.entity.BizGroup;
import vip.xiaonuo.biz.modular.group.param.*;
import vip.xiaonuo.biz.modular.group.service.BizGroupService;
import vip.xiaonuo.biz.modular.user.entity.BizUser;
import vip.xiaonuo.common.annotation.CommonLog;
import vip.xiaonuo.common.pojo.CommonResult;
import vip.xiaonuo.biz.modular.group.entity.BizGroup;
import vip.xiaonuo.biz.modular.group.service.BizGroupService;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import java.util.List;
/**

View File

@ -12,7 +12,8 @@
*/
package vip.xiaonuo.biz.modular.group.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;

View File

@ -2,4 +2,4 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="vip.xiaonuo.biz.modular.group.mapper.BizGroupMapper">
</mapper>
</mapper>

View File

@ -13,10 +13,10 @@
package vip.xiaonuo.biz.modular.group.param;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
/**
*

View File

@ -13,10 +13,10 @@
package vip.xiaonuo.biz.modular.group.param;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
/**
*

View File

@ -13,11 +13,10 @@
package vip.xiaonuo.biz.modular.group.param;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
import jakarta.validation.constraints.NotBlank;
/**
* Id
*

View File

@ -21,7 +21,6 @@ import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -29,17 +28,18 @@ import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.biz.modular.group.entity.BizGroup;
import vip.xiaonuo.biz.modular.group.mapper.BizGroupMapper;
import vip.xiaonuo.biz.modular.group.param.*;
import vip.xiaonuo.biz.modular.group.service.BizGroupService;
import vip.xiaonuo.biz.modular.org.entity.BizOrg;
import vip.xiaonuo.biz.modular.org.service.BizOrgService;
import vip.xiaonuo.biz.modular.user.entity.BizUser;
import vip.xiaonuo.biz.modular.user.enums.BizUserStatusEnum;
import vip.xiaonuo.biz.modular.user.service.BizUserService;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.biz.modular.group.entity.BizGroup;
import vip.xiaonuo.biz.modular.group.mapper.BizGroupMapper;
import vip.xiaonuo.biz.modular.group.service.BizGroupService;
import vip.xiaonuo.sys.api.SysGroupApi;
import java.util.List;
@ -143,32 +143,34 @@ public class BizGroupServiceImpl extends ServiceImpl<BizGroupMapper, BizGroup> i
@Override
public Page<BizUser> userSelector(BizGroupSelectorUserParam bizGroupSelectorUserParam) {
LambdaQueryWrapper<BizUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
QueryWrapper<BizUser> queryWrapper = new QueryWrapper<BizUser>().checkSqlInjection();
// 只查询状态为正常的
queryWrapper.lambda().eq(BizUser::getUserStatus, BizUserStatusEnum.ENABLE.getValue());
// 校验数据范围
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
lambdaQueryWrapper.in(BizUser::getOrgId, loginUserDataScope);
queryWrapper.lambda().in(BizUser::getOrgId, loginUserDataScope);
} else {
return new Page<>();
}
// 只查询部分字段
lambdaQueryWrapper.select(BizUser::getId, BizUser::getAvatar, BizUser::getOrgId, BizUser::getPositionId, BizUser::getAccount,
queryWrapper.lambda().select(BizUser::getId, BizUser::getAvatar, BizUser::getOrgId, BizUser::getPositionId, BizUser::getAccount,
BizUser::getName, BizUser::getSortCode, BizUser::getGender, BizUser::getEntryDate);
if (ObjectUtil.isNotEmpty(bizGroupSelectorUserParam.getOrgId())) {
// 如果机构id不为空则查询该机构及其子机构下的所有人
List<String> childOrgIdList = CollStreamUtil.toList(bizOrgService.getChildListById(bizOrgService
.getAllOrgList(), bizGroupSelectorUserParam.getOrgId(), true), BizOrg::getId);
if (ObjectUtil.isNotEmpty(childOrgIdList)) {
lambdaQueryWrapper.in(BizUser::getOrgId, childOrgIdList);
queryWrapper.lambda().in(BizUser::getOrgId, childOrgIdList);
} else {
return new Page<>();
}
}
if(ObjectUtil.isNotEmpty(bizGroupSelectorUserParam.getSearchKey())) {
lambdaQueryWrapper.like(BizUser::getName, bizGroupSelectorUserParam.getSearchKey());
queryWrapper.lambda().like(BizUser::getName, bizGroupSelectorUserParam.getSearchKey());
}
lambdaQueryWrapper.orderByAsc(BizUser::getSortCode);
return bizUserService.page(CommonPageRequest.defaultPage(), lambdaQueryWrapper);
queryWrapper.lambda().orderByAsc(BizUser::getSortCode);
return bizUserService.page(CommonPageRequest.defaultPage(), queryWrapper);
}
@Override

View File

@ -15,10 +15,11 @@ package vip.xiaonuo.biz.modular.org.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
@ -26,12 +27,14 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import vip.xiaonuo.biz.modular.org.entity.BizOrg;
import vip.xiaonuo.biz.modular.org.enums.BizOrgSourceFromTypeEnum;
import vip.xiaonuo.biz.modular.org.param.*;
import vip.xiaonuo.biz.modular.org.service.BizOrgService;
import vip.xiaonuo.biz.modular.user.entity.BizUser;
import vip.xiaonuo.common.annotation.CommonLog;
import vip.xiaonuo.common.pojo.CommonResult;
import javax.validation.Valid;
import java.util.List;
/**
@ -41,6 +44,7 @@ import java.util.List;
* @date 2022/4/24 19:55
*/
@Tag(name = "机构控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 1)
@RestController
@Validated
public class BizOrgController {
@ -54,6 +58,7 @@ public class BizOrgController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 1)
@Operation(summary = "获取机构分页")
@SaCheckPermission("/biz/org/page")
@GetMapping("/biz/org/page")
@ -67,6 +72,7 @@ public class BizOrgController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 2)
@Operation(summary = "获取机构树")
@SaCheckPermission("/biz/org/tree")
@GetMapping("/biz/org/tree")
@ -80,12 +86,13 @@ public class BizOrgController {
* @author xuyuxiang
* @date 2022/4/24 20:47
*/
@ApiOperationSupport(order = 3)
@Operation(summary = "添加机构")
@CommonLog("添加机构")
@SaCheckPermission("/biz/org/add")
@PostMapping("/biz/org/add")
public CommonResult<String> add(@RequestBody @Valid BizOrgAddParam bizOrgAddParam) {
bizOrgService.add(bizOrgAddParam);
bizOrgService.add(bizOrgAddParam, BizOrgSourceFromTypeEnum.SYSTEM_ADD.getValue());
return CommonResult.ok();
}
@ -95,6 +102,7 @@ public class BizOrgController {
* @author xuyuxiang
* @date 2022/4/24 20:47
*/
@ApiOperationSupport(order = 4)
@Operation(summary = "编辑机构")
@CommonLog("编辑机构")
@SaCheckPermission("/biz/org/edit")
@ -110,6 +118,7 @@ public class BizOrgController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 5)
@Operation(summary = "删除机构")
@CommonLog("删除机构")
@SaCheckPermission("/biz/org/delete")
@ -126,6 +135,7 @@ public class BizOrgController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 6)
@Operation(summary = "获取机构详情")
@SaCheckPermission("/biz/org/detail")
@GetMapping("/biz/org/detail")
@ -141,6 +151,7 @@ public class BizOrgController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 7)
@Operation(summary = "获取机构树选择器")
@SaCheckPermission("/biz/org/orgTreeSelector")
@GetMapping("/biz/org/orgTreeSelector")
@ -154,6 +165,7 @@ public class BizOrgController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 8)
@Operation(summary = "获取人员选择器")
@SaCheckPermission("/biz/org/userSelector")
@GetMapping("/biz/org/userSelector")

View File

@ -44,7 +44,7 @@ public class BizOrg extends CommonEntity {
/** 主管id */
@Schema(description = "主管id")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
@Trans(type = TransType.SIMPLE, target = BizUser.class, fields = "name", alias = "director", ref = "directorName")
private String directorId;
@ -66,6 +66,6 @@ public class BizOrg extends CommonEntity {
/** 扩展信息 */
@Schema(description = "扩展信息")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String extJson;
}

View File

@ -0,0 +1,46 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.biz.modular.org.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import vip.xiaonuo.common.pojo.CommonEntity;
/**
*
*
* @author xuyuxiang
* @date 2022/4/21 16:13
**/
@Getter
@Setter
@TableName("SYS_ORG_EXT")
public class BizOrgExt extends CommonEntity {
/** id */
@TableId
@Schema(description = "id")
private String id;
/** 机构id */
@Schema(description = "机构id")
private String orgId;
/** 来源类别 */
@Schema(description = "来源类别")
private String sourceFromType;
}

View File

@ -0,0 +1,37 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.biz.modular.org.enums;
import lombok.Getter;
/**
*
*
* @author xuyuxiang
* @date 2022/4/21 19:56
**/
@Getter
public enum BizOrgSourceFromTypeEnum {
/** 系统自建 */
SYSTEM_ADD("SYSTEM_ADD"),
/** 身份源 */
ID_SOURCE("ID_SOURCE");
private final String value;
BizOrgSourceFromTypeEnum(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.biz.modular.org.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vip.xiaonuo.biz.modular.org.entity.BizOrgExt;
/**
* Mapper
*
* @author xuyuxiang
* @date 2022/4/21 18:37
**/
public interface BizOrgExtMapper extends BaseMapper<BizOrgExt> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="vip.xiaonuo.biz.modular.org.mapper.BizOrgExtMapper">
</mapper>

View File

@ -29,22 +29,22 @@ import lombok.Setter;
public class BizOrgAddParam {
/** 父id */
@Schema(description = "父id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "父id")
@NotBlank(message = "parentId不能为空")
private String parentId;
/** 名称 */
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "名称")
@NotBlank(message = "name不能为空")
private String name;
/** 分类 */
@Schema(description = "分类", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "分类")
@NotBlank(message = "category不能为空")
private String category;
/** 排序码 */
@Schema(description = "排序码", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "排序码")
@NotNull(message = "sortCode不能为空")
private Integer sortCode;

View File

@ -29,27 +29,27 @@ import lombok.Setter;
public class BizOrgEditParam {
/** id */
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "id")
@NotBlank(message = "id不能为空")
private String id;
/** 父id */
@Schema(description = "父id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "父id")
@NotBlank(message = "parentId不能为空")
private String parentId;
/** 名称 */
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "名称")
@NotBlank(message = "name不能为空")
private String name;
/** 分类 */
@Schema(description = "分类", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "分类")
@NotBlank(message = "category不能为空")
private String category;
/** 排序码 */
@Schema(description = "排序码", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "排序码")
@NotNull(message = "sortCode不能为空")
private Integer sortCode;

View File

@ -28,7 +28,7 @@ import lombok.Setter;
public class BizOrgIdParam {
/** id */
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "id")
@NotBlank(message = "id不能为空")
private String id;
}

View File

@ -21,6 +21,7 @@ import org.springframework.stereotype.Service;
import vip.xiaonuo.biz.api.BizOrgApi;
import vip.xiaonuo.biz.modular.org.param.BizOrgSelectorOrgListParam;
import vip.xiaonuo.biz.modular.org.service.BizOrgService;
import java.util.List;
/**

View File

@ -0,0 +1,33 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.biz.modular.org.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vip.xiaonuo.biz.modular.org.entity.BizOrgExt;
/**
* Service
*
* @author yubaoshan
* @date 2024/12/21 01:25
**/
public interface BizOrgExtService extends IService<BizOrgExt> {
/**
*
*
* @author xuyuxiang
* @date 2022/4/27 21:38
*/
void createExtInfo(String orgId, String sourceFromType);
}

View File

@ -51,7 +51,7 @@ public interface BizOrgService extends IService<BizOrg> {
* @author xuyuxiang
* @date 2022/4/24 20:48
*/
void add(BizOrgAddParam bizOrgAddParam);
void add(BizOrgAddParam bizOrgAddParam, String sourceFromType);
/**
*

View File

@ -0,0 +1,37 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.biz.modular.org.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import vip.xiaonuo.biz.modular.org.entity.BizOrgExt;
import vip.xiaonuo.biz.modular.org.mapper.BizOrgExtMapper;
import vip.xiaonuo.biz.modular.org.service.BizOrgExtService;
/**
* Service
*
* @author yubaoshan
* @date 2024/12/21 01:25
**/
@Service
public class BizOrgExtServiceImpl extends ServiceImpl<BizOrgExtMapper, BizOrgExt> implements BizOrgExtService {
@Override
public void createExtInfo(String orgId, String sourceFromType) {
BizOrgExt bizOrgExt = new BizOrgExt();
bizOrgExt.setOrgId(orgId);
bizOrgExt.setSourceFromType(sourceFromType);
this.save(bizOrgExt);
}
}

View File

@ -36,18 +36,19 @@ import vip.xiaonuo.biz.modular.org.entity.BizOrg;
import vip.xiaonuo.biz.modular.org.enums.BizOrgCategoryEnum;
import vip.xiaonuo.biz.modular.org.mapper.BizOrgMapper;
import vip.xiaonuo.biz.modular.org.param.*;
import vip.xiaonuo.biz.modular.org.service.BizOrgExtService;
import vip.xiaonuo.biz.modular.org.service.BizOrgService;
import vip.xiaonuo.biz.modular.position.entity.BizPosition;
import vip.xiaonuo.biz.modular.position.service.BizPositionService;
import vip.xiaonuo.biz.modular.user.entity.BizUser;
import vip.xiaonuo.biz.modular.user.service.BizUserService;
import vip.xiaonuo.common.cache.CommonCacheOperator;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.listener.CommonDataChangeEventCenter;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.sys.api.SysRoleApi;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@ -62,14 +63,12 @@ import java.util.stream.Collectors;
@Service
public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> implements BizOrgService {
public static final String ORG_CACHE_ALL_KEY = "sys-org:all";
@Resource
private CommonCacheOperator commonCacheOperator;
@Resource
private SysRoleApi sysRoleApi;
@Resource
private BizOrgExtService bizOrgExtService;
@Resource
private BizPositionService bizPositionService;
@ -127,7 +126,7 @@ public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> impleme
@Transactional(rollbackFor = Exception.class)
@Override
public void add(BizOrgAddParam bizOrgAddParam) {
public void add(BizOrgAddParam bizOrgAddParam, String sourceFromType) {
BizOrgCategoryEnum.validate(bizOrgAddParam.getCategory());
// 校验数据范围
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
@ -147,8 +146,10 @@ public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> impleme
throw new CommonException("存在重复的同级机构,名称为:{}", bizOrg.getName());
}
bizOrg.setCode(RandomUtil.randomString(10));
// 保存机构
this.save(bizOrg);
// 插入扩展信息
bizOrgExtService.createExtInfo(bizOrg.getId(), sourceFromType);
// 发布增加事件
CommonDataChangeEventCenter.doAddWithData(BizDataTypeEnum.ORG.getValue(), JSONUtil.createArray().put(bizOrg));
}
@ -182,8 +183,8 @@ public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> impleme
if(errorLevel) {
throw new CommonException("不可选择上级机构:{}", this.getById(originDataList, bizOrg.getParentId()).getName());
}
// 更新机构
this.updateById(bizOrg);
// 发布更新事件
CommonDataChangeEventCenter.doUpdateWithData(BizDataTypeEnum.ORG.getValue(), JSONUtil.createArray().put(bizOrg));
}
@ -196,7 +197,7 @@ public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> impleme
// 校验数据范围
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
if(!loginUserDataScope.containsAll(orgIdList)) {
if(!new HashSet<>(loginUserDataScope).containsAll(orgIdList)) {
throw new CommonException("您没有权限删除这些机构机构id{}", orgIdList);
}
} else {
@ -219,7 +220,7 @@ public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> impleme
List<String> positionOrgIdList = CollectionUtil.newArrayList();
positionJsonList.forEach(positionJson -> JSONUtil.toList(JSONUtil.parseArray(positionJson), JSONObject.class)
.forEach(jsonObject -> positionOrgIdList.add(jsonObject.getStr("orgId"))));
boolean hasPositionUser = CollectionUtil.intersectionDistinct(toDeleteOrgIdList, CollectionUtil.removeNull(positionOrgIdList)).size() > 0;
boolean hasPositionUser = !CollectionUtil.intersectionDistinct(toDeleteOrgIdList, CollectionUtil.removeNull(positionOrgIdList)).isEmpty();
if(hasPositionUser) {
throw new CommonException("请先删除机构下的人员");
}
@ -263,28 +264,28 @@ public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> impleme
@Override
public String getOrgIdByOrgFullNameWithCreate(String orgFullName) {
List<BizOrg> cachedAllOrgList = this.getAllOrgList();
List<Tree<String>> treeList = TreeUtil.build(cachedAllOrgList.stream().map(bizOrg ->
List<BizOrg> allOrgList = this.getAllOrgList();
List<Tree<String>> treeList = TreeUtil.build(allOrgList.stream().map(bizOrg ->
new TreeNode<>(bizOrg.getId(), bizOrg.getParentId(), bizOrg.getName(), bizOrg.getSortCode()))
.collect(Collectors.toList()), "0");
return findOrgIdByOrgName("0", StrUtil.split(orgFullName, StrUtil.DASHED).iterator(), cachedAllOrgList, treeList);
return findOrgIdByOrgName("0", StrUtil.split(orgFullName, StrUtil.DASHED).iterator(), allOrgList, treeList);
}
public String findOrgIdByOrgName(String parentId, Iterator<String> iterator, List<BizOrg> cachedAllOrgList, List<Tree<String>> treeList) {
public String findOrgIdByOrgName(String parentId, Iterator<String> iterator, List<BizOrg> allOrgList, List<Tree<String>> treeList) {
String orgName = iterator.next();
if(ObjectUtil.isNotEmpty(treeList)) {
List<Tree<String>> findList = treeList.stream().filter(tree -> tree.getName().equals(orgName)).collect(Collectors.toList());
if(ObjectUtil.isNotEmpty(findList)) {
if(iterator.hasNext()) {
return findOrgIdByOrgName(findList.get(0).getId(), iterator, cachedAllOrgList, findList.get(0).getChildren());
return findOrgIdByOrgName(findList.get(0).getId(), iterator, allOrgList, findList.get(0).getChildren());
} else {
return findList.get(0).getId();
}
}
}
String orgId = this.doCreateOrg(parentId, orgName, cachedAllOrgList);
String orgId = this.doCreateOrg(parentId, orgName, allOrgList);
if(iterator.hasNext()) {
return findOrgIdByOrgName(orgId, iterator, cachedAllOrgList, CollectionUtil.newArrayList());
return findOrgIdByOrgName(orgId, iterator, allOrgList, CollectionUtil.newArrayList());
} else {
return orgId;
}
@ -296,7 +297,7 @@ public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> impleme
* @author xuyuxiang
* @date 2023/3/8 9:38
**/
public String doCreateOrg(String parentId, String orgName, List<BizOrg> cachedAllOrgList) {
public String doCreateOrg(String parentId, String orgName, List<BizOrg> allOrgList) {
//创建该机构
BizOrg bizOrg = new BizOrg();
bizOrg.setName(orgName);
@ -307,10 +308,6 @@ public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> impleme
this.save(bizOrg);
// 发布增加事件
CommonDataChangeEventCenter.doAddWithData(BizDataTypeEnum.ORG.getValue(), JSONUtil.createArray().put(bizOrg));
// 将该机构加入缓存
cachedAllOrgList.add(bizOrg);
// 更新缓存
commonCacheOperator.put(ORG_CACHE_ALL_KEY, cachedAllOrgList);
return bizOrg.getId();
}
@ -342,55 +339,55 @@ public class BizOrgServiceImpl extends ServiceImpl<BizOrgMapper, BizOrg> impleme
@Override
public List<BizOrg> orgListSelector(BizOrgSelectorOrgListParam bizOrgSelectorOrgListParam) {
LambdaQueryWrapper<BizOrg> lambdaQueryWrapper = new LambdaQueryWrapper<>();
QueryWrapper<BizOrg> queryWrapper = new QueryWrapper<BizOrg>().checkSqlInjection();
// 校验数据范围
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
lambdaQueryWrapper.in(BizOrg::getId, loginUserDataScope);
queryWrapper.lambda().in(BizOrg::getId, loginUserDataScope);
} else {
return CollectionUtil.newArrayList();
}
// 查询部分字段
lambdaQueryWrapper.select(BizOrg::getId, BizOrg::getParentId, BizOrg::getName,
queryWrapper.lambda().select(BizOrg::getId, BizOrg::getParentId, BizOrg::getName,
BizOrg::getCategory, BizOrg::getSortCode);
if(ObjectUtil.isNotEmpty(bizOrgSelectorOrgListParam.getParentId())) {
lambdaQueryWrapper.eq(BizOrg::getParentId, bizOrgSelectorOrgListParam.getParentId());
queryWrapper.lambda().eq(BizOrg::getParentId, bizOrgSelectorOrgListParam.getParentId());
}
if(ObjectUtil.isNotEmpty(bizOrgSelectorOrgListParam.getSearchKey())) {
lambdaQueryWrapper.like(BizOrg::getName, bizOrgSelectorOrgListParam.getSearchKey());
queryWrapper.lambda().like(BizOrg::getName, bizOrgSelectorOrgListParam.getSearchKey());
}
lambdaQueryWrapper.orderByAsc(BizOrg::getSortCode);
return this.list(lambdaQueryWrapper);
queryWrapper.lambda().orderByAsc(BizOrg::getSortCode);
return this.list(queryWrapper.lambda());
}
@Override
public Page<BizUser> userSelector(BizOrgSelectorUserParam bizOrgSelectorUserParam) {
LambdaQueryWrapper<BizUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
QueryWrapper<BizUser> queryWrapper = new QueryWrapper<BizUser>().checkSqlInjection();
// 校验数据范围
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
lambdaQueryWrapper.in(BizUser::getOrgId, loginUserDataScope);
queryWrapper.lambda().in(BizUser::getOrgId, loginUserDataScope);
} else {
return new Page<>();
}
// 只查询部分字段
lambdaQueryWrapper.select(BizUser::getId, BizUser::getAvatar, BizUser::getOrgId, BizUser::getPositionId, BizUser::getAccount,
queryWrapper.lambda().select(BizUser::getId, BizUser::getAvatar, BizUser::getOrgId, BizUser::getPositionId, BizUser::getAccount,
BizUser::getName, BizUser::getSortCode, BizUser::getGender, BizUser::getEntryDate);
if (ObjectUtil.isNotEmpty(bizOrgSelectorUserParam.getOrgId())) {
// 如果机构id不为空则查询该机构及其子机构下的所有人
List<String> childOrgIdList = CollStreamUtil.toList(this.getChildListById(this
.getAllOrgList(), bizOrgSelectorUserParam.getOrgId(), true), BizOrg::getId);
if (ObjectUtil.isNotEmpty(childOrgIdList)) {
lambdaQueryWrapper.in(BizUser::getOrgId, childOrgIdList);
queryWrapper.lambda().in(BizUser::getOrgId, childOrgIdList);
} else {
return new Page<>();
}
}
if(ObjectUtil.isNotEmpty(bizOrgSelectorUserParam.getSearchKey())) {
lambdaQueryWrapper.like(BizUser::getName, bizOrgSelectorUserParam.getSearchKey());
queryWrapper.lambda().like(BizUser::getName, bizOrgSelectorUserParam.getSearchKey());
}
lambdaQueryWrapper.orderByAsc(BizUser::getSortCode);
return bizUserService.page(CommonPageRequest.defaultPage(), lambdaQueryWrapper);
queryWrapper.lambda().orderByAsc(BizUser::getSortCode);
return bizUserService.page(CommonPageRequest.defaultPage(), queryWrapper.lambda());
}
/* ====以下为各种递归方法==== */

View File

@ -15,10 +15,11 @@ package vip.xiaonuo.biz.modular.position.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
@ -31,6 +32,7 @@ import vip.xiaonuo.biz.modular.position.service.BizPositionService;
import vip.xiaonuo.common.annotation.CommonLog;
import vip.xiaonuo.common.pojo.CommonResult;
import javax.validation.Valid;
import java.util.List;
/**
@ -40,6 +42,7 @@ import java.util.List;
* @date 2022/4/25 20:40
*/
@Tag(name = "岗位控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 2)
@RestController
@Validated
public class BizPositionController {
@ -53,6 +56,7 @@ public class BizPositionController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 1)
@Operation(summary = "获取岗位分页")
@SaCheckPermission("/biz/position/page")
@GetMapping("/biz/position/page")
@ -66,6 +70,7 @@ public class BizPositionController {
* @author xuyuxiang
* @date 2022/4/24 20:47
*/
@ApiOperationSupport(order = 2)
@Operation(summary = "添加岗位")
@CommonLog("添加岗位")
@SaCheckPermission("/biz/position/add")
@ -81,6 +86,7 @@ public class BizPositionController {
* @author xuyuxiang
* @date 2022/4/24 20:47
*/
@ApiOperationSupport(order = 3)
@Operation(summary = "编辑岗位")
@CommonLog("编辑岗位")
@SaCheckPermission("/biz/position/edit")
@ -96,6 +102,7 @@ public class BizPositionController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 4)
@Operation(summary = "删除岗位")
@CommonLog("删除岗位")
@SaCheckPermission("/biz/position/delete")
@ -112,6 +119,7 @@ public class BizPositionController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 5)
@Operation(summary = "获取岗位详情")
@SaCheckPermission("/biz/position/detail")
@GetMapping("/biz/position/detail")
@ -127,6 +135,7 @@ public class BizPositionController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 6)
@Operation(summary = "获取组织树选择器")
@SaCheckPermission("/biz/position/orgTreeSelector")
@GetMapping("/biz/position/orgTreeSelector")
@ -140,6 +149,7 @@ public class BizPositionController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 7)
@Operation(summary = "获取岗位选择器")
@SaCheckPermission("/biz/position/positionSelector")
@GetMapping("/biz/position/positionSelector")

View File

@ -57,6 +57,6 @@ public class BizPosition extends CommonEntity {
/** 扩展信息 */
@Schema(description = "扩展信息")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String extJson;
}

View File

@ -29,22 +29,22 @@ import lombok.Setter;
public class BizPositionAddParam {
/** 机构id */
@Schema(description = "机构id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "机构id")
@NotBlank(message = "orgId不能为空")
private String orgId;
/** 名称 */
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "名称")
@NotBlank(message = "name不能为空")
private String name;
/** 分类 */
@Schema(description = "分类", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "分类")
@NotBlank(message = "category不能为空")
private String category;
/** 排序码 */
@Schema(description = "排序码", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "排序码")
@NotNull(message = "sortCode不能为空")
private Integer sortCode;

View File

@ -29,27 +29,27 @@ import lombok.Setter;
public class BizPositionEditParam {
/** id */
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "id")
@NotBlank(message = "id不能为空")
private String id;
/** 机构id */
@Schema(description = "机构id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "机构id")
@NotBlank(message = "orgId不能为空")
private String orgId;
/** 名称 */
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "名称")
@NotBlank(message = "name不能为空")
private String name;
/** 分类 */
@Schema(description = "分类", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "分类")
@NotBlank(message = "category不能为空")
private String category;
/** 排序码 */
@Schema(description = "排序码", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "排序码")
@NotNull(message = "sortCode不能为空")
private Integer sortCode;

View File

@ -28,7 +28,7 @@ import lombok.Setter;
public class BizPositionIdParam {
/** id */
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "id")
@NotBlank(message = "id不能为空")
private String id;
}

View File

@ -47,6 +47,7 @@ import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.listener.CommonDataChangeEventCenter;
import vip.xiaonuo.common.page.CommonPageRequest;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@ -71,7 +72,7 @@ public class BizPositionServiceImpl extends ServiceImpl<BizPositionMapper, BizPo
QueryWrapper<BizPosition> queryWrapper = new QueryWrapper<BizPosition>().checkSqlInjection();
// 查询部分字段
queryWrapper.lambda().select(BizPosition::getId, BizPosition::getOrgId, BizPosition::getName,
BizPosition::getCategory, BizPosition::getSortCode);
BizPosition::getCategory, BizPosition::getSortCode, BizPosition::getExtJson);
if(ObjectUtil.isNotEmpty(bizPositionPageParam.getOrgId())) {
queryWrapper.lambda().eq(BizPosition::getOrgId, bizPositionPageParam.getOrgId());
}
@ -162,7 +163,7 @@ public class BizPositionServiceImpl extends ServiceImpl<BizPositionMapper, BizPo
// 校验数据范围
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
if(!loginUserDataScope.containsAll(positionOrgIdList)) {
if(!new HashSet<>(loginUserDataScope).containsAll(positionOrgIdList)) {
throw new CommonException("您没有权限删除这些机构下的岗位机构id{}", positionOrgIdList);
}
} else {
@ -180,7 +181,7 @@ public class BizPositionServiceImpl extends ServiceImpl<BizPositionMapper, BizPo
List<String> extPositionIdList = CollectionUtil.newArrayList();
positionJsonList.forEach(positionJson -> JSONUtil.toList(JSONUtil.parseArray(positionJson), JSONObject.class)
.forEach(jsonObject -> extPositionIdList.add(jsonObject.getStr("positionId"))));
boolean hasPositionUser = CollectionUtil.intersectionDistinct(positionIdList, CollectionUtil.removeNull(extPositionIdList)).size() > 0;
boolean hasPositionUser = !CollectionUtil.intersectionDistinct(positionIdList, CollectionUtil.removeNull(extPositionIdList)).isEmpty();
if(hasPositionUser) {
throw new CommonException("请先删除岗位下的用户");
}
@ -240,24 +241,24 @@ public class BizPositionServiceImpl extends ServiceImpl<BizPositionMapper, BizPo
@Override
public Page<BizPosition> positionSelector(BizPositionSelectorPositionParam bizPositionSelectorPositionParam) {
LambdaQueryWrapper<BizPosition> lambdaQueryWrapper = new LambdaQueryWrapper<>();
QueryWrapper<BizPosition> queryWrapper = new QueryWrapper<BizPosition>();
// 校验数据范围
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
lambdaQueryWrapper.in(BizPosition::getOrgId, loginUserDataScope);
queryWrapper.lambda().in(BizPosition::getOrgId, loginUserDataScope);
} else {
return new Page<>();
}
// 查询部分字段
lambdaQueryWrapper.select(BizPosition::getId, BizPosition::getOrgId, BizPosition::getName,
queryWrapper.lambda().select(BizPosition::getId, BizPosition::getOrgId, BizPosition::getName,
BizPosition::getCategory, BizPosition::getSortCode);
if(ObjectUtil.isNotEmpty(bizPositionSelectorPositionParam.getOrgId())) {
lambdaQueryWrapper.eq(BizPosition::getOrgId, bizPositionSelectorPositionParam.getOrgId());
queryWrapper.lambda().eq(BizPosition::getOrgId, bizPositionSelectorPositionParam.getOrgId());
}
if(ObjectUtil.isNotEmpty(bizPositionSelectorPositionParam.getSearchKey())) {
lambdaQueryWrapper.like(BizPosition::getName, bizPositionSelectorPositionParam.getSearchKey());
queryWrapper.lambda().like(BizPosition::getName, bizPositionSelectorPositionParam.getSearchKey());
}
lambdaQueryWrapper.orderByAsc(BizPosition::getSortCode);
return this.page(CommonPageRequest.defaultPage(), lambdaQueryWrapper);
queryWrapper.lambda().orderByAsc(BizPosition::getSortCode);
return this.page(CommonPageRequest.defaultPage(), queryWrapper.lambda());
}
}

View File

@ -15,11 +15,12 @@ package vip.xiaonuo.biz.modular.user.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
@ -30,12 +31,14 @@ import org.springframework.web.bind.annotation.RestController;
import vip.xiaonuo.biz.modular.org.entity.BizOrg;
import vip.xiaonuo.biz.modular.position.entity.BizPosition;
import vip.xiaonuo.biz.modular.user.entity.BizUser;
import vip.xiaonuo.biz.modular.user.enums.BizUserSourceFromTypeEnum;
import vip.xiaonuo.biz.modular.user.param.*;
import vip.xiaonuo.biz.modular.user.result.BizUserRoleResult;
import vip.xiaonuo.biz.modular.user.service.BizUserService;
import vip.xiaonuo.common.annotation.CommonLog;
import vip.xiaonuo.common.pojo.CommonResult;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
@ -46,6 +49,7 @@ import java.util.List;
* @date 2022/4/22 9:34
**/
@Tag(name = "人员控制器")
@ApiSupport(author = "SNOWY_TEAM", order = 9)
@RestController
@Validated
public class BizUserController {
@ -59,6 +63,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 1)
@Operation(summary = "获取人员分页")
@SaCheckPermission("/biz/user/page")
@GetMapping("/biz/user/page")
@ -72,12 +77,13 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:47
*/
@ApiOperationSupport(order = 2)
@Operation(summary = "添加人员")
@CommonLog("添加人员")
@SaCheckPermission("/biz/user/add")
@PostMapping("/biz/user/add")
public CommonResult<String> add(@RequestBody @Valid BizUserAddParam bizUserAddParam) {
bizUserService.add(bizUserAddParam);
bizUserService.add(bizUserAddParam, BizUserSourceFromTypeEnum.SYSTEM_ADD.getValue());
return CommonResult.ok();
}
@ -87,6 +93,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:47
*/
@ApiOperationSupport(order = 3)
@Operation(summary = "编辑人员")
@CommonLog("编辑人员")
@SaCheckPermission("/biz/user/edit")
@ -102,6 +109,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 4)
@Operation(summary = "删除人员")
@CommonLog("删除人员")
@SaCheckPermission("/biz/user/delete")
@ -118,6 +126,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 5)
@Operation(summary = "获取人员详情")
@SaCheckPermission("/biz/user/detail")
@GetMapping("/biz/user/detail")
@ -131,6 +140,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2021/10/13 14:01
**/
@ApiOperationSupport(order = 6)
@Operation(summary = "禁用人员")
@CommonLog("禁用人员")
@SaCheckPermission("/biz/user/disableUser")
@ -146,6 +156,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2021/10/13 14:01
**/
@ApiOperationSupport(order = 7)
@Operation(summary = "启用人员")
@CommonLog("启用人员")
@SaCheckPermission("/biz/user/enableUser")
@ -161,6 +172,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2021/10/13 14:01
**/
@ApiOperationSupport(order = 8)
@Operation(summary = "重置人员密码")
@CommonLog("重置人员密码")
@SaCheckPermission("/biz/user/resetPassword")
@ -176,6 +188,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 9)
@Operation(summary = "获取人员拥有角色")
@SaCheckPermission("/biz/user/ownRole")
@GetMapping("/biz/user/ownRole")
@ -189,6 +202,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 10)
@Operation(summary = "给人员授权角色")
@CommonLog("给人员授权角色")
@SaCheckPermission("/biz/user/grantRole")
@ -204,6 +218,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 11)
@Operation(summary = "人员导出")
@CommonLog("人员导出")
@SaCheckPermission("/biz/user/export")
@ -218,6 +233,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 12)
@Operation(summary = "导出人员个人信息")
@CommonLog("导出人员个人信息")
@SaCheckPermission("/biz/user/exportUserInfo")
@ -234,6 +250,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 13)
@Operation(summary = "获取机构树选择器")
@SaCheckPermission("/biz/user/orgTreeSelector")
@GetMapping("/biz/user/orgTreeSelector")
@ -247,6 +264,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 14)
@Operation(summary = "获取机构列表选择器")
@SaCheckPermission("/biz/user/orgListSelector")
@GetMapping("/biz/user/orgListSelector")
@ -260,6 +278,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 15)
@Operation(summary = "获取岗位选择器")
@SaCheckPermission("/biz/user/positionSelector")
@GetMapping("/biz/user/positionSelector")
@ -273,6 +292,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 16)
@Operation(summary = "获取角色选择器")
@SaCheckPermission("/biz/user/roleSelector")
@GetMapping("/biz/user/roleSelector")
@ -286,6 +306,7 @@ public class BizUserController {
* @author xuyuxiang
* @date 2022/4/24 20:00
*/
@ApiOperationSupport(order = 17)
@Operation(summary = "获取人员选择器")
@SaCheckPermission("/biz/user/userSelector")
@GetMapping("/biz/user/userSelector")

View File

@ -47,12 +47,12 @@ public class BizUser extends CommonEntity {
/** 头像 */
@Schema(description = "头像")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String avatar;
/** 签名 */
@Schema(description = "签名")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String signature;
/** 账号 */
@ -70,156 +70,154 @@ public class BizUser extends CommonEntity {
/** 昵称 */
@Schema(description = "昵称")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String nickname;
/** 性别 */
@Schema(description = "性别")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
@Trans(type = TransType.DICTIONARY, key = "GENDER")
private String gender;
/** 年龄 */
@Schema(description = "年龄")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String age;
/** 出生日期 */
@Schema(description = "出生日期")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String birthday;
/** 民族 */
@Schema(description = "民族")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String nation;
/** 籍贯 */
@Schema(description = "籍贯")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String nativePlace;
/** 家庭住址 */
@Schema(description = "家庭住址")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String homeAddress;
/** 通信地址 */
@Schema(description = "通信地址")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String mailingAddress;
/** 证件类型 */
@Schema(description = "证件类型")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String idCardType;
/** 证件号码 */
@Schema(description = "证件号码")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED, typeHandler = CommonSm4CbcTypeHandler.class)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS, typeHandler = CommonSm4CbcTypeHandler.class)
private String idCardNumber;
/** 文化程度 */
@Schema(description = "文化程度")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String cultureLevel;
/** 政治面貌 */
@Schema(description = "政治面貌")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String politicalOutlook;
/** 毕业院校 */
@Schema(description = "毕业院校")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String college;
/** 学历 */
@Schema(description = "学历")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String education;
/** 学制 */
@Schema(description = "学制")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String eduLength;
/** 学位 */
@Schema(description = "学位")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String degree;
/** 手机 */
@Schema(description = "手机")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED, typeHandler = CommonSm4CbcTypeHandler.class)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS, typeHandler = CommonSm4CbcTypeHandler.class)
private String phone;
/** 邮箱 */
@Schema(description = "邮箱")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String email;
/** 家庭电话 */
@Schema(description = "家庭电话")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String homeTel;
/** 办公电话 */
@Schema(description = "办公电话")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String officeTel;
/** 紧急联系人 */
@Schema(description = "紧急联系人")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String emergencyContact;
/** 紧急联系人电话 */
@Schema(description = "紧急联系人电话")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED, typeHandler = CommonSm4CbcTypeHandler.class)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS, typeHandler = CommonSm4CbcTypeHandler.class)
private String emergencyPhone;
/** 紧急联系人地址 */
@Schema(description = "紧急联系人地址")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String emergencyAddress;
/** 员工编号 */
@Schema(description = "员工编号")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String empNo;
/** 入职日期 */
@Schema(description = "入职日期")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String entryDate;
/** 机构id */
@Schema(description = "机构id")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@Trans(type = TransType.SIMPLE, target = BizOrg.class, fields = "name", alias = "org", ref = "orgName")
private String orgId;
/** 岗位id */
@Schema(description = "岗位id")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@Trans(type = TransType.SIMPLE, target = BizPosition.class, fields = "name", alias = "position", ref = "positionName")
private String positionId;
/** 职级 */
@Schema(description = "职级")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String positionLevel;
/** 主管id */
@Schema(description = "主管id")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
@Trans(type = TransType.SIMPLE, target = BizUser.class, fields = "name", alias = "director", ref = "directorName")
private String directorId;
/** 兼任信息 */
@Schema(description = "兼任信息")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String positionJson;
/** 上次登录ip */
@ -264,7 +262,7 @@ public class BizUser extends CommonEntity {
/** 扩展信息 */
@Schema(description = "扩展信息")
@TableField(insertStrategy = FieldStrategy.IGNORED, updateStrategy = FieldStrategy.IGNORED)
@TableField(insertStrategy = FieldStrategy.ALWAYS, updateStrategy = FieldStrategy.ALWAYS)
private String extJson;
@Schema(description = "机构名称")

View File

@ -0,0 +1,52 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.biz.modular.user.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import vip.xiaonuo.common.pojo.CommonEntity;
import java.util.Date;
/**
*
*
* @author xuyuxiang
* @date 2022/4/21 16:13
**/
@Getter
@Setter
@TableName("SYS_USER_EXT")
public class BizUserExt extends CommonEntity {
/** id */
@TableId
@Schema(description = "id")
private String id;
/** 用户id */
@Schema(description = "用户id")
private String userId;
/** 来源类别 */
@Schema(description = "来源类别")
private String sourceFromType;
/** 密码修改日期 */
@Schema(description = "密码修改日期")
private Date passwordUpdateTime;
}

View File

@ -0,0 +1,40 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.biz.modular.user.enums;
import lombok.Getter;
/**
*
*
* @author xuyuxiang
* @date 2022/4/21 19:56
**/
@Getter
public enum BizUserSourceFromTypeEnum {
/** 系统自建 */
SYSTEM_ADD("SYSTEM_ADD"),
/** 用户注册 */
SYSTEM_REGISTER("SYSTEM_REGISTER"),
/** 身份源 */
ID_SOURCE("ID_SOURCE");
private final String value;
BizUserSourceFromTypeEnum(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.biz.modular.user.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vip.xiaonuo.biz.modular.user.entity.BizUserExt;
/**
* Mapper
*
* @author xuyuxiang
* @date 2022/4/21 18:37
**/
public interface BizUserExtMapper extends BaseMapper<BizUserExt> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="vip.xiaonuo.biz.modular.user.mapper.BizUserExtMapper">
</mapper>

View File

@ -2,4 +2,4 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="vip.xiaonuo.biz.modular.user.mapper.BizUserMapper">
</mapper>
</mapper>

View File

@ -28,22 +28,22 @@ import lombok.Setter;
public class BizUserAddParam {
/** 账号 */
@Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "账号")
@NotBlank(message = "account不能为空")
private String account;
/** 姓名 */
@Schema(description = "姓名", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "姓名")
@NotBlank(message = "name不能为空")
private String name;
/** 机构id */
@Schema(description = "机构id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "机构id")
@NotBlank(message = "orgId不能为空")
private String orgId;
/** 岗位id */
@Schema(description = "岗位id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "岗位id")
@NotBlank(message = "positionId不能为空")
private String positionId;

View File

@ -28,27 +28,27 @@ import lombok.Setter;
public class BizUserEditParam {
/** id */
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "id")
@NotBlank(message = "id不能为空")
private String id;
/** 账号 */
@Schema(description = "账号", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "账号")
@NotBlank(message = "account不能为空")
private String account;
/** 姓名 */
@Schema(description = "姓名", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "姓名")
@NotBlank(message = "name不能为空")
private String name;
/** 机构id */
@Schema(description = "机构id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "机构id")
@NotBlank(message = "orgId不能为空")
private String orgId;
/** 岗位id */
@Schema(description = "岗位id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "岗位id")
@NotBlank(message = "positionId不能为空")
private String positionId;

View File

@ -31,12 +31,12 @@ import java.util.List;
public class BizUserGrantRoleParam {
/** id */
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "id")
@NotBlank(message = "id不能为空")
private String id;
/** 角色id集合 */
@Schema(description = "角色id集合", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "角色id集合")
@NotNull(message = "roleIdList不能为空")
private List<String> roleIdList;
}

View File

@ -28,7 +28,7 @@ import lombok.Setter;
public class BizUserIdParam {
/** id */
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "id")
@NotBlank(message = "id不能为空")
private String id;
}

View File

@ -0,0 +1,41 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.biz.modular.user.service;
import com.baomidou.mybatisplus.extension.service.IService;
import vip.xiaonuo.biz.modular.user.entity.BizUserExt;
/**
* Service
*
* @author yubaoshan
* @date 2024/12/21 01:25
**/
public interface BizUserExtService extends IService<BizUserExt> {
/**
*
*
* @author xuyuxiang
* @date 2022/4/27 21:38
*/
void updatePasswordLastTime(String userId);
/**
*
*
* @author xuyuxiang
* @date 2022/4/27 21:38
*/
void createExtInfo(String userId, String sourceFromType);
}

View File

@ -47,7 +47,7 @@ public interface BizUserService extends IService<BizUser> {
* @author xuyuxiang
* @date 2022/4/24 20:48
*/
void add(BizUserAddParam bizUserAddParam);
void add(BizUserAddParam bizUserAddParam, String sourceFromType);
/**
*
@ -83,7 +83,7 @@ public interface BizUserService extends IService<BizUser> {
/**
*
*
*
* @author xuyuxiang
* @date 2022/7/5 18:20
**/

View File

@ -0,0 +1,55 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.biz.modular.user.service.impl;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import vip.xiaonuo.biz.modular.user.entity.BizUserExt;
import vip.xiaonuo.biz.modular.user.mapper.BizUserExtMapper;
import vip.xiaonuo.biz.modular.user.service.BizUserExtService;
/**
* Service
*
* @author yubaoshan
* @date 2024/12/21 01:25
**/
@Service
public class BizUserExtServiceImpl extends ServiceImpl<BizUserExtMapper, BizUserExt> implements BizUserExtService {
@Override
public void updatePasswordLastTime(String userId) {
BizUserExt bizUserExt = this.getOne(new LambdaQueryWrapper<BizUserExt>().eq(BizUserExt::getUserId, userId));
if(ObjectUtil.isEmpty(bizUserExt)){
bizUserExt = new BizUserExt();
bizUserExt.setUserId(userId);
bizUserExt.setPasswordUpdateTime(DateTime.now());
this.save(bizUserExt);
} else {
bizUserExt.setPasswordUpdateTime(DateTime.now());
this.updateById(bizUserExt);
}
}
@Override
public void createExtInfo(String userId, String sourceFromType) {
BizUserExt bizUserExt = new BizUserExt();
bizUserExt.setUserId(userId);
bizUserExt.setSourceFromType(sourceFromType);
bizUserExt.setPasswordUpdateTime(DateTime.now());
this.save(bizUserExt);
}
}

View File

@ -61,12 +61,14 @@ import vip.xiaonuo.biz.modular.org.service.BizOrgService;
import vip.xiaonuo.biz.modular.position.entity.BizPosition;
import vip.xiaonuo.biz.modular.position.service.BizPositionService;
import vip.xiaonuo.biz.modular.user.entity.BizUser;
import vip.xiaonuo.biz.modular.user.entity.BizUserExt;
import vip.xiaonuo.biz.modular.user.enums.BizRoleCategoryEnum;
import vip.xiaonuo.biz.modular.user.enums.BizUserStatusEnum;
import vip.xiaonuo.biz.modular.user.mapper.BizUserMapper;
import vip.xiaonuo.biz.modular.user.param.*;
import vip.xiaonuo.biz.modular.user.result.BizUserExportResult;
import vip.xiaonuo.biz.modular.user.result.BizUserRoleResult;
import vip.xiaonuo.biz.modular.user.service.BizUserExtService;
import vip.xiaonuo.biz.modular.user.service.BizUserService;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.excel.CommonExcelCustomMergeStrategy;
@ -74,7 +76,7 @@ import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.listener.CommonDataChangeEventCenter;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.common.util.*;
import vip.xiaonuo.dev.api.DevConfigApi;
import vip.xiaonuo.sys.api.SysApi;
import vip.xiaonuo.sys.api.SysRoleApi;
import vip.xiaonuo.sys.api.SysUserApi;
@ -82,10 +84,7 @@ import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -97,13 +96,11 @@ import java.util.stream.Collectors;
@Service
public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> implements BizUserService {
private static final String SNOWY_SYS_DEFAULT_PASSWORD_KEY = "SNOWY_SYS_DEFAULT_PASSWORD";
@Resource
private TransService transService;
@Resource
private DevConfigApi devConfigApi;
private SysApi sysApi;
@Resource
private SysUserApi sysUserApi;
@ -111,6 +108,9 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
@Resource
private SysRoleApi sysRoleApi;
@Resource
private BizUserExtService bizUserExtService;
@Resource
private BizOrgService bizOrgService;
@ -151,7 +151,7 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
@Transactional(rollbackFor = Exception.class)
@Override
public void add(BizUserAddParam bizUserAddParam) {
public void add(BizUserAddParam bizUserAddParam, String sourceFromType) {
checkParam(bizUserAddParam);
BizUser bizUser = BeanUtil.toBean(bizUserAddParam, BizUser.class);
if(ObjectUtil.isEmpty(bizUser.getAvatar())) {
@ -159,11 +159,13 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
bizUser.setAvatar(CommonAvatarUtil.generateImg(bizUser.getName()));
}
// 设置密码
bizUser.setPassword(CommonCryptogramUtil.doHashValue(devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_PASSWORD_KEY)));
bizUser.setPassword(CommonCryptogramUtil.doHashValue(sysApi.getDefaultPassword()));
// 设置状态
bizUser.setUserStatus(BizUserStatusEnum.ENABLE.getValue());
// 保存用户
this.save(bizUser);
// 插入扩展信息
bizUserExtService.createExtInfo(bizUser.getId(), sourceFromType);
// 发布增加事件
CommonDataChangeEventCenter.doAddWithData(BizDataTypeEnum.USER.getValue(), JSONUtil.createArray().put(bizUser));
}
@ -192,7 +194,7 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
}
}
if(ObjectUtil.isNotEmpty(bizUserAddParam.getEmail())) {
if(!CommonEmailUtil.isEmail(bizUserAddParam.getEmail())) {
if(CommonEmailUtil.isNotEmail(bizUserAddParam.getEmail())) {
throw new CommonException("邮箱:{}格式错误", bizUserAddParam.getEmail());
}
if (this.count(new LambdaQueryWrapper<BizUser>()
@ -213,8 +215,8 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
throw new CommonException("不可修改系统内置超管人员账号");
}
BeanUtil.copyProperties(bizUserEditParam, bizUser);
// 更新用户
this.updateById(bizUser);
// 发布更新事件
CommonDataChangeEventCenter.doUpdateWithData(BizDataTypeEnum.USER.getValue(), JSONUtil.createArray().put(bizUser));
}
@ -247,7 +249,7 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
}
}
if(ObjectUtil.isNotEmpty(bizUserEditParam.getEmail())) {
if(!CommonEmailUtil.isEmail(bizUserEditParam.getEmail())) {
if(CommonEmailUtil.isNotEmail(bizUserEditParam.getEmail())) {
throw new CommonException("邮箱:{}格式错误", bizUserEditParam.getEmail());
}
if (this.count(new LambdaQueryWrapper<BizUser>()
@ -273,7 +275,7 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
// 校验数据范围
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
if(!loginUserDataScope.containsAll(userOrgIdList)) {
if(!new HashSet<>(loginUserDataScope).containsAll(userOrgIdList)) {
throw new CommonException("您没有权限删除这些机构下的人员机构id{}",
CollectionUtil.subtract(userOrgIdList, loginUserDataScope));
}
@ -304,6 +306,9 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
// 执行删除
this.removeByIds(bizUserIdList);
// 删除扩展信息
bizUserExtService.remove(new LambdaQueryWrapper<BizUserExt>().in(BizUserExt::getUserId, bizUserIdList));
// 发布删除事件
CommonDataChangeEventCenter.doDeleteWithDataId(BizDataTypeEnum.USER.getValue(), bizUserIdList);
}
@ -369,7 +374,7 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
}
this.update(new LambdaUpdateWrapper<BizUser>().eq(BizUser::getId,
bizUserIdParam.getId()).set(BizUser::getPassword,
CommonCryptogramUtil.doHashValue(devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_PASSWORD_KEY))));
CommonCryptogramUtil.doHashValue(sysApi.getDefaultPassword())));
}
@Override
@ -563,7 +568,7 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
if(ObjectUtil.isNotEmpty(bizUser.getBirthday())) {
try {
// 年龄
long age = cn.hutool.core.date.DateUtil.betweenYear(cn.hutool.core.date.DateUtil.parseDate(bizUser.getBirthday()), DateTime.now(), true);
long age = DateUtil.betweenYear(DateUtil.parseDate(bizUser.getBirthday()), DateTime.now(), true);
if(age != 0) {
map.put("age", age + "岁");
}
@ -633,48 +638,48 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
@Override
public Page<BizOrg> orgListSelector(BizUserSelectorOrgListParam bizUserSelectorOrgListParam) {
LambdaQueryWrapper<BizOrg> lambdaQueryWrapper = new LambdaQueryWrapper<>();
QueryWrapper<BizOrg> queryWrapper = new QueryWrapper<BizOrg>().checkSqlInjection();
// 校验数据范围
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
lambdaQueryWrapper.in(BizOrg::getId, loginUserDataScope);
queryWrapper.lambda().in(BizOrg::getId, loginUserDataScope);
} else {
return new Page<>();
}
// 查询部分字段
lambdaQueryWrapper.select(BizOrg::getId, BizOrg::getParentId, BizOrg::getName,
queryWrapper.lambda().select(BizOrg::getId, BizOrg::getParentId, BizOrg::getName,
BizOrg::getCategory, BizOrg::getSortCode);
if(ObjectUtil.isNotEmpty(bizUserSelectorOrgListParam.getParentId())) {
lambdaQueryWrapper.eq(BizOrg::getParentId, bizUserSelectorOrgListParam.getParentId());
queryWrapper.lambda().eq(BizOrg::getParentId, bizUserSelectorOrgListParam.getParentId());
}
if(ObjectUtil.isNotEmpty(bizUserSelectorOrgListParam.getSearchKey())) {
lambdaQueryWrapper.like(BizOrg::getName, bizUserSelectorOrgListParam.getSearchKey());
queryWrapper.lambda().like(BizOrg::getName, bizUserSelectorOrgListParam.getSearchKey());
}
lambdaQueryWrapper.orderByAsc(BizOrg::getSortCode);
return bizOrgService.page(CommonPageRequest.defaultPage(), lambdaQueryWrapper);
queryWrapper.lambda().orderByAsc(BizOrg::getSortCode);
return bizOrgService.page(CommonPageRequest.defaultPage(), queryWrapper.lambda());
}
@Override
public Page<BizPosition> positionSelector(BizUserSelectorPositionParam bizUserSelectorPositionParam) {
LambdaQueryWrapper<BizPosition> lambdaQueryWrapper = new LambdaQueryWrapper<>();
QueryWrapper<BizPosition> queryWrapper = new QueryWrapper<BizPosition>().checkSqlInjection();
// 校验数据范围
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
lambdaQueryWrapper.in(BizPosition::getOrgId, loginUserDataScope);
queryWrapper.lambda().in(BizPosition::getOrgId, loginUserDataScope);
} else {
return new Page<>();
}
// 查询部分字段
lambdaQueryWrapper.select(BizPosition::getId, BizPosition::getOrgId, BizPosition::getName,
queryWrapper.lambda().select(BizPosition::getId, BizPosition::getOrgId, BizPosition::getName,
BizPosition::getCategory, BizPosition::getSortCode);
if(ObjectUtil.isNotEmpty(bizUserSelectorPositionParam.getOrgId())) {
lambdaQueryWrapper.eq(BizPosition::getOrgId, bizUserSelectorPositionParam.getOrgId());
queryWrapper.lambda().eq(BizPosition::getOrgId, bizUserSelectorPositionParam.getOrgId());
}
if(ObjectUtil.isNotEmpty(bizUserSelectorPositionParam.getSearchKey())) {
lambdaQueryWrapper.like(BizPosition::getName, bizUserSelectorPositionParam.getSearchKey());
queryWrapper.lambda().like(BizPosition::getName, bizUserSelectorPositionParam.getSearchKey());
}
lambdaQueryWrapper.orderByAsc(BizPosition::getSortCode);
return bizPositionService.page(CommonPageRequest.defaultPage(), lambdaQueryWrapper);
queryWrapper.lambda().orderByAsc(BizPosition::getSortCode);
return bizPositionService.page(CommonPageRequest.defaultPage(), queryWrapper.lambda());
}
@SuppressWarnings("ALL")
@ -707,31 +712,31 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
@Override
public Page<BizUser> userSelector(BizUserSelectorUserParam bizUserSelectorUserParam) {
LambdaQueryWrapper<BizUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
QueryWrapper<BizUser> queryWrapper = new QueryWrapper<BizUser>().checkSqlInjection();
// 校验数据范围
List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
lambdaQueryWrapper.in(BizUser::getOrgId, loginUserDataScope);
queryWrapper.lambda().in(BizUser::getOrgId, loginUserDataScope);
} else {
return new Page<>();
}
// 只查询部分字段
lambdaQueryWrapper.select(BizUser::getId, BizUser::getAvatar, BizUser::getOrgId, BizUser::getPositionId, BizUser::getAccount,
queryWrapper.lambda().select(BizUser::getId, BizUser::getAvatar, BizUser::getOrgId, BizUser::getPositionId, BizUser::getAccount,
BizUser::getName, BizUser::getSortCode, BizUser::getGender, BizUser::getEntryDate);
if (ObjectUtil.isNotEmpty(bizUserSelectorUserParam.getOrgId())) {
// 如果机构id不为空则查询该机构及其子机构下的所有人
List<String> childOrgIdList = CollStreamUtil.toList(bizOrgService.getChildListById(bizOrgService
.getAllOrgList(), bizUserSelectorUserParam.getOrgId(), true), BizOrg::getId);
if (ObjectUtil.isNotEmpty(childOrgIdList)) {
lambdaQueryWrapper.in(BizUser::getOrgId, childOrgIdList);
queryWrapper.lambda().in(BizUser::getOrgId, childOrgIdList);
} else {
return new Page<>();
}
}
if(ObjectUtil.isNotEmpty(bizUserSelectorUserParam.getSearchKey())) {
lambdaQueryWrapper.like(BizUser::getName, bizUserSelectorUserParam.getSearchKey());
queryWrapper.lambda().like(BizUser::getName, bizUserSelectorUserParam.getSearchKey());
}
lambdaQueryWrapper.orderByAsc(BizUser::getSortCode);
return this.page(CommonPageRequest.defaultPage(), lambdaQueryWrapper);
queryWrapper.lambda().orderByAsc(BizUser::getSortCode);
return this.page(CommonPageRequest.defaultPage(), queryWrapper.lambda());
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.client.core.enums;
import lombok.Getter;
/**
*
*
* @author xuyuxiang
* @date 2023/3/3 10:40
**/
@Getter
public enum ClientPasswordComplexityEnum {
/**
*
*/
REG0("REG0", "无限制"),
/**
*
*/
REG1("REG1", "必须包含数字和字母"),
/**
*
*/
REG2("REG2", "必须包含数字和大写字母"),
/**
*
*/
REG3("REG3", "必须包含数字、大写字母、小写字母和特殊字符"),
/**
*
*/
REG4("REG4", "至少包含数字、字母和特殊字符中的两种"),
/**
*
*/
REG5("REG5", "至少包含数字、大写字母、小写字母和特殊字符的三种");
private final String value;
private final String message;
ClientPasswordComplexityEnum(String value, String message) {
this.value = value;
this.message = message;
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright [2022] [https://www.xiaonuo.vip]
*
* SnowyAPACHE LICENSE 2.0使
*
* 1.LICENSE
* 2.Snowy
* 3.使使
* 4. https://www.xiaonuo.vip
* 5.xiaonuobase@qq.com
* 6.Snowy https://www.xiaonuo.vip
*/
package vip.xiaonuo.client.core.timer;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import vip.xiaonuo.client.modular.user.service.ClientUserService;
import vip.xiaonuo.common.timer.CommonTimerTaskRunner;
/**
*
*
* @author xuyuxiang
* @date 2022/8/5 15:52
**/
@Slf4j
@Component
public class ClientUserPasswordExpiredNoticeTimerTaskRunner implements CommonTimerTaskRunner {
@Resource
private ClientUserService clientUserService;
@Override
public void action(String extJson) {
// 通知用户密码即将到期
clientUserService.noticeUserPasswordAboutToExpired();
}
}

Some files were not shown because too many files have changed in this diff Show More