thiszhc
2023-06-16 aec0e227479de49213185ff6bb98d4e99b35eb8b
Merge branch '5.X' of https://gitee.com/dromara/RuoYi-Vue-Plus into JustAuth

# Conflicts:
# ruoyi-admin/src/main/resources/application-dev.yml
已添加3个文件
已重命名2个文件
已删除5个文件
已修改24个文件
943 ■■■■■ 文件已修改
README.md 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-dev.yml 181 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-prod.yml 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/pom.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-sms/pom.xml 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsConfig.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/AliyunSmsTemplate.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/SmsTemplate.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/TencentSmsTemplate.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/entity/SmsResult.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/exception/SmsException.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/pom.xml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
@@ -57,7 +57,7 @@
| åˆ†å¸ƒå¼ä»»åŠ¡è°ƒåº¦     | é‡‡ç”¨ Xxl-Job å¤©ç”Ÿæ”¯æŒåˆ†å¸ƒå¼ ç»Ÿä¸€çš„管理中心                                                                                        | é‡‡ç”¨ Quartz åŸºäºŽæ•°æ®åº“锁性能差 é›†ç¾¤éœ€è¦åšå¾ˆå¤šé…ç½®ä¸Žæ”¹é€                                                    | 
| æ–‡ä»¶å­˜å‚¨        | é‡‡ç”¨ Minio åˆ†å¸ƒå¼æ–‡ä»¶å­˜å‚¨ å¤©ç”Ÿæ”¯æŒå¤šæœºã€å¤šç¡¬ç›˜ã€å¤šåˆ†ç‰‡ã€å¤šå‰¯æœ¬å­˜å‚¨<br/>支持权限管理 å®‰å…¨å¯é  æ–‡ä»¶å¯åŠ å¯†å­˜å‚¨                                                     | é‡‡ç”¨ æœ¬æœºæ–‡ä»¶å­˜å‚¨ æ–‡ä»¶è£¸æ¼ æ˜“丢失泄漏 ä¸æ”¯æŒé›†ç¾¤æœ‰å•点效应                                                    |
| äº‘存储         | é‡‡ç”¨ AWS S3 åè®®å®¢æˆ·ç«¯ æ”¯æŒ ä¸ƒç‰›ã€é˜¿é‡Œã€è…¾è®¯ ç­‰ä¸€åˆ‡æ”¯æŒS3协议的厂家                                                                          | ä¸æ”¯æŒ                                                                                |
| çŸ­ä¿¡          | æ”¯æŒ é˜¿é‡Œã€è…¾è®¯ åªéœ€åœ¨yml配置好厂家密钥即可使用 æŽ¥å£åŒ–支持扩展其他厂家                                                                            | ä¸æ”¯æŒ                                                                                |
| çŸ­ä¿¡          | é‡‡ç”¨ sms4j çŸ­ä¿¡èžåˆåŒ… æ”¯æŒæ•°åç§çŸ­ä¿¡åނ家 åªéœ€åœ¨yml配置好厂家密钥即可使用 å¯å¤šåŽ‚å®¶å…±ç”¨                                                                 | ä¸æ”¯æŒ                                                                                |
| é‚®ä»¶          | é‡‡ç”¨ mail-api é€šç”¨åè®®æ”¯æŒå¤§éƒ¨åˆ†é‚®ä»¶åނ商                                                                                         | ä¸æ”¯æŒ                                                                                |
| æŽ¥å£æ–‡æ¡£        | é‡‡ç”¨ SpringDoc、javadoc æ— æ³¨è§£é›¶å…¥ä¾µåŸºäºŽjava注释<br/>只需把注释写好 æ— éœ€å†å†™ä¸€å¤§å †çš„æ–‡æ¡£æ³¨è§£äº†                                                     | é‡‡ç”¨ Springfox å·²åœæ­¢ç»´æŠ¤ éœ€è¦ç¼–写大量的注解来支持文档生成                                                | 
| æ ¡éªŒæ¡†æž¶        | é‡‡ç”¨ Validation æ”¯æŒæ³¨è§£ä¸Žå·¥å…·ç±»æ ¡éªŒ æ³¨è§£æ”¯æŒå›½é™…化                                                                                  | ä»…支持注解 ä¸”注解不支持国际化                                                                    |
pom.xml
@@ -49,8 +49,7 @@
        <!-- OSS é…ç½® -->
        <aws-java-sdk-s3.version>1.12.400</aws-java-sdk-s3.version>
        <!-- SMS é…ç½® -->
        <aliyun.sms.version>2.0.23</aliyun.sms.version>
        <tencent.sms.version>3.1.687</tencent.sms.version>
        <sms4j.version>2.1.1</sms4j.version>
        <!-- æ’件版本 -->
        <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
@@ -242,17 +241,11 @@
                <artifactId>aws-java-sdk-s3</artifactId>
                <version>${aws-java-sdk-s3.version}</version>
            </dependency>
            <!--短信sms4j-->
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>dysmsapi20170525</artifactId>
                <version>${aliyun.sms.version}</version>
            </dependency>
            <dependency>
                <groupId>com.tencentcloudapi</groupId>
                <artifactId>tencentcloud-sdk-java-sms</artifactId>
                <version>${tencent.sms.version}</version>
                <groupId>org.dromara.sms4j</groupId>
                <artifactId>sms4j-spring-boot-starter</artifactId>
                <version>${sms4j.version}</version>
            </dependency>
            <dependency>
ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java
@@ -14,11 +14,12 @@
import org.dromara.common.mail.config.properties.MailProperties;
import org.dromara.common.mail.utils.MailUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.sms.config.properties.SmsProperties;
import org.dromara.common.sms.core.SmsTemplate;
import org.dromara.common.sms.entity.SmsResult;
import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.common.web.enums.CaptchaType;
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.dromara.sms4j.provider.enumerate.SupplierType;
import org.dromara.web.domain.vo.CaptchaVo;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
@@ -31,8 +32,7 @@
import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedHashMap;
/**
 * éªŒè¯ç æ“ä½œå¤„理
@@ -47,7 +47,6 @@
public class CaptchaController {
    private final CaptchaProperties captchaProperties;
    private final SmsProperties smsProperties;
    private final MailProperties mailProperties;
    /**
@@ -57,21 +56,18 @@
     */
    @GetMapping("/resource/sms/code")
    public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
        if (!smsProperties.getEnabled()) {
            return R.fail("当前系统没有开启短信功能!");
        }
        String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber;
        String code = RandomUtil.randomNumbers(4);
        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
        // éªŒè¯ç æ¨¡æ¿id è‡ªè¡Œå¤„理 (查数据库或写死均可)
        String templateId = "";
        Map<String, String> map = new HashMap<>(1);
        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
        map.put("code", code);
        SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class);
        SmsResult result = smsTemplate.send(phonenumber, templateId, map);
        if (!result.isSuccess()) {
            log.error("验证码短信发送异常 => {}", result);
            return R.fail(result.getMessage());
        SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
        SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
        if (!"OK".equals(smsResponse.getCode())) {
            log.error("验证码短信发送异常 => {}", smsResponse);
            return R.fail(smsResponse.getMessage());
        }
        return R.ok();
    }
ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
@@ -345,7 +345,7 @@
    private SysUserVo loadUserByEmail(String tenantId, String email) {
        SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
            .select(SysUser::getPhonenumber, SysUser::getStatus)
            .select(SysUser::getEmail, SysUser::getStatus)
            .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId)
            .eq(SysUser::getEmail, email));
        if (ObjectUtil.isNull(user)) {
@@ -414,25 +414,24 @@
        String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username;
        String loginFail = Constants.LOGIN_FAIL;
        // èŽ·å–ç”¨æˆ·ç™»å½•é”™è¯¯æ¬¡æ•°(可自定义限制策略 ä¾‹å¦‚: key + username + ip)
        Integer errorNumber = RedisUtils.getCacheObject(errorKey);
        // èŽ·å–ç”¨æˆ·ç™»å½•é”™è¯¯æ¬¡æ•°ï¼Œé»˜è®¤ä¸º0 (可自定义限制策略 ä¾‹å¦‚: key + username + ip)
        int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0);
        // é”å®šæ—¶é—´å†…登录 åˆ™è¸¢å‡º
        if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(maxRetryCount)) {
        if (errorNumber >= maxRetryCount) {
            recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
            throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
        }
        if (supplier.get()) {
            // æ˜¯å¦ç¬¬ä¸€æ¬¡
            errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
            // é”™è¯¯æ¬¡æ•°é€’增
            errorNumber++;
            RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
            // è¾¾åˆ°è§„定错误次数 åˆ™é”å®šç™»å½•
            if (errorNumber.equals(maxRetryCount)) {
                RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
            if (errorNumber >= maxRetryCount) {
                recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
                throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
            } else {
                // æœªè¾¾åˆ°è§„定错误次数 åˆ™é€’增
                RedisUtils.setCacheObject(errorKey, errorNumber);
                // æœªè¾¾åˆ°è§„定错误次数
                recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber));
                throw new UserException(loginType.getRetryLimitCount(), errorNumber);
            }
ruoyi-admin/src/main/resources/application-dev.yml
@@ -158,162 +158,29 @@
  # Socket连接超时值,单位毫秒,缺省值不超时
  connectionTimeout: 0
--- # sms çŸ­ä¿¡
--- # sms çŸ­ä¿¡ æ”¯æŒ é˜¿é‡Œäº‘ è…¾è®¯äº‘ äº‘片 ç­‰ç­‰å„式各样的短信服务商
# https://wind.kim/doc/start æ–‡æ¡£åœ°å€ å„个厂商可同时使用
sms:
  enabled: false
  # é˜¿é‡Œäº‘ dysmsapi.aliyuncs.com
  # è…¾è®¯äº‘ sms.tencentcloudapi.com
  endpoint: "dysmsapi.aliyuncs.com"
  accessKeyId: xxxxxxx
  accessKeySecret: xxxxxx
  signName: æµ‹è¯•
  # è…¾è®¯ä¸“用
  sdkAppId:
justauth:
  enabled: true
  type:
    QQ:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/qq/callback
      union-id: false
    WEIBO:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/weibo/callback
    gitee:
      client-id: 38eaaa1b77b5e064313057a2f5745ce3a9f3e7686d9bd302c7df2f308ef6db81
      client-secret: 2e633af8780cb9fe002c4c7291b722db944402e271efb99b062811f52d7da1ff
      redirect-uri: http://localhost:8888/social-login?source=gitee
    DINGTALK:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/dingtalk/callback
    BAIDU:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/baidu/callback
    CSDN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/csdn/callback
    CODING:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/coding/callback
      coding-group-name: xx
    OSCHINA:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/oschina/callback
    ALIPAY:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/alipay/callback
      alipay-public-key: MIIB**************DAQAB
    WECHAT_OPEN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_open/callback
    WECHAT_MP:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_mp/callback
    WECHAT_ENTERPRISE:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_enterprise/callback
      agent-id: 1000002
    TAOBAO:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/taobao/callback
    GOOGLE:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/google/callback
    FACEBOOK:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/facebook/callback
    DOUYIN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/douyin/callback
    LINKEDIN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/linkedin/callback
    MICROSOFT:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/microsoft/callback
    MI:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/mi/callback
    TOUTIAO:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/toutiao/callback
    TEAMBITION:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/teambition/callback
    RENREN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/renren/callback
    PINTEREST:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/pinterest/callback
    STACK_OVERFLOW:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/stack_overflow/callback
      stack-overflow-key: asd*********asd
    HUAWEI:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/huawei/callback
    KUJIALE:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/kujiale/callback
    GITLAB:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/gitlab/callback
    MEITUAN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/meituan/callback
    ELEME:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/eleme/callback
    TWITTER:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/twitter/callback
    XMLY:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/xmly/callback
      # è®¾å¤‡å”¯ä¸€æ ‡è¯†ID
      device-id: xxxxxxxxxxxxxx
      # å®¢æˆ·ç«¯æ“ä½œç³»ç»Ÿç±»åž‹ï¼Œ1-iOS系统,2-Android系统,3-Web
      client-os-type: 3
      # å®¢æˆ·ç«¯åŒ…名,如果 clientOsType ä¸º1或2时必填。对Android客户端是包名,对IOS客户端是Bundle ID
      #pack-id: xxxx
    FEISHU:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/feishu/callback
    JD:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/jd/callback
  alibaba:
    #请求地址 é»˜è®¤ä¸º dysmsapi.aliyuncs.com å¦‚无特殊改变可以不用设置
    requestUrl: dysmsapi.aliyuncs.com
    #阿里云的accessKey
    accessKeyId: xxxxxxx
    #阿里云的accessKeySecret
    accessKeySecret: xxxxxxx
    #短信签名
    signature: æµ‹è¯•
  tencent:
    #请求地址默认为 sms.tencentcloudapi.com å¦‚无特殊改变可不用设置
    requestUrl: sms.tencentcloudapi.com
    #腾讯云的accessKey
    accessKeyId: xxxxxxx
    #腾讯云的accessKeySecret
    accessKeySecret: xxxxxxx
    #短信签名
    signature: æµ‹è¯•
    #短信sdkAppId
    sdkAppId: appid
    #地域信息默认为 ap-guangzhou å¦‚无特殊改变可不用设置
    territory: ap-guangzhou
ruoyi-admin/src/main/resources/application-prod.yml
@@ -161,14 +161,29 @@
  # Socket连接超时值,单位毫秒,缺省值不超时
  connectionTimeout: 0
--- # sms çŸ­ä¿¡
--- # sms çŸ­ä¿¡ æ”¯æŒ é˜¿é‡Œäº‘ è…¾è®¯äº‘ äº‘片 ç­‰ç­‰å„式各样的短信服务商
# https://wind.kim/doc/start æ–‡æ¡£åœ°å€ å„个厂商可同时使用
sms:
  enabled: false
  # é˜¿é‡Œäº‘ dysmsapi.aliyuncs.com
  # è…¾è®¯äº‘ sms.tencentcloudapi.com
  endpoint: "dysmsapi.aliyuncs.com"
  accessKeyId: xxxxxxx
  accessKeySecret: xxxxxx
  signName: æµ‹è¯•
  # è…¾è®¯ä¸“用
  sdkAppId:
  alibaba:
    #请求地址 é»˜è®¤ä¸º dysmsapi.aliyuncs.com å¦‚无特殊改变可以不用设置
    requestUrl: dysmsapi.aliyuncs.com
    #阿里云的accessKey
    accessKeyId: xxxxxxx
    #阿里云的accessKeySecret
    accessKeySecret: xxxxxxx
    #短信签名
    signature: æµ‹è¯•
  tencent:
    #请求地址默认为 sms.tencentcloudapi.com å¦‚无特殊改变可不用设置
    requestUrl: sms.tencentcloudapi.com
    #腾讯云的accessKey
    accessKeyId: xxxxxxx
    #腾讯云的accessKeySecret
    accessKeySecret: xxxxxxx
    #短信签名
    signature: æµ‹è¯•
    #短信sdkAppId
    sdkAppId: appid
    #地域信息默认为 ap-guangzhou å¦‚无特殊改变可不用设置
    territory: ap-guangzhou
ruoyi-admin/src/main/resources/application.yml
@@ -96,20 +96,14 @@
sa-token:
  # token名称 (同时也是cookie名称)
  token-name: Authorization
  # token有效期 è®¾ä¸ºä¸€å¤© (必定过期) å•位: ç§’
  timeout: 86400
  # token临时有效期 (指定时间无操作就过期) å•位: ç§’
  # token固定超时 è®¾ä¸ºä¸ƒå¤© (必定过期) å•位: ç§’
  timeout: 604800
  # token活跃超时时间 30分钟(指定时间无操作则过期) å•位: ç§’
  activity-timeout: 1800
  # æ˜¯å¦å…è®¸åŒä¸€è´¦å·å¹¶å‘登录 (为true时允许一起登录, ä¸ºfalse时新登录挤掉旧登录)
  is-concurrent: true
  # åœ¨å¤šäººç™»å½•同一账号时,是否共用一个token (为true时所有登录共用一个token, ä¸ºfalse时每次登录新建一个token)
  is-share: false
  # æ˜¯å¦å°è¯•从header里读取token
  is-read-header: true
  # æ˜¯å¦å°è¯•从cookie里读取token
  is-read-cookie: false
  # token前缀
  token-prefix: "Bearer"
  # jwt秘钥
  jwt-secret-key: abcdefghijklmnopqrstuvwxyz
@@ -156,39 +150,12 @@
  mapperLocations: classpath*:mapper/**/*Mapper.xml
  # å®žä½“扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: org.dromara.**.domain
  # å¯åŠ¨æ—¶æ˜¯å¦æ£€æŸ¥ MyBatis XML æ–‡ä»¶çš„存在,默认不检查
  checkConfigLocation: false
  configuration:
    # è‡ªåŠ¨é©¼å³°å‘½åè§„åˆ™ï¼ˆcamel case)映射
    mapUnderscoreToCamelCase: true
    # MyBatis è‡ªåŠ¨æ˜ å°„ç­–ç•¥
    # NONE:不启用 PARTIAL:只对非嵌套 resultMap è‡ªåŠ¨æ˜ å°„ FULL:对所有 resultMap è‡ªåŠ¨æ˜ å°„
    autoMappingBehavior: FULL
    # MyBatis è‡ªåŠ¨æ˜ å°„æ—¶æœªçŸ¥åˆ—æˆ–æœªçŸ¥å±žæ€§å¤„ç†ç­–
    # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
    autoMappingUnknownColumnBehavior: NONE
    # æ›´è¯¦ç»†çš„æ—¥å¿—输出 ä¼šæœ‰æ€§èƒ½æŸè€— org.apache.ibatis.logging.stdout.StdOutImpl
    # å…³é—­æ—¥å¿—记录 (可单纯使用 p6spy åˆ†æž) org.apache.ibatis.logging.nologging.NoLoggingImpl
    # é»˜è®¤æ—¥å¿—输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
    logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
  global-config:
    # æ˜¯å¦æ‰“印 Logo banner
    banner: true
    dbConfig:
      # ä¸»é”®ç±»åž‹
      # AUTO è‡ªå¢ž NONE ç©º INPUT ç”¨æˆ·è¾“å…¥ ASSIGN_ID é›ªèб ASSIGN_UUID å”¯ä¸€ UUID
      # å¦‚需改为自增 éœ€è¦å°†æ•°æ®åº“表全部设置为自增
      idType: ASSIGN_ID
      # é€»è¾‘已删除值
      logicDeleteValue: 2
      # é€»è¾‘未删除值
      logicNotDeleteValue: 0
      # å­—段验证策略之 insert,在 insert çš„æ—¶å€™çš„字段验证策略
      # IGNORED å¿½ç•¥ NOT_NULL éžNULL NOT_EMPTY éžç©º DEFAULT é»˜è®¤ NEVER ä¸åŠ å…¥ SQL
      insertStrategy: NOT_NULL
      # å­—段验证策略之 update,在 update çš„æ—¶å€™çš„字段验证策略
      updateStrategy: NOT_NULL
      # å­—段验证策略之 select,在 select çš„æ—¶å€™çš„字段验证策略既 wrapper æ ¹æ®å†…部 entity ç”Ÿæˆçš„ where æ¡ä»¶
      where-strategy: NOT_NULL
# æ•°æ®åР坆
mybatis-encryptor:
@@ -204,8 +171,13 @@
  publicKey:
  privateKey:
# Swagger配置
swagger:
springdoc:
  api-docs:
    # æ˜¯å¦å¼€å¯æŽ¥å£æ–‡æ¡£
    enabled: true
  swagger-ui:
    # æŒä¹…化认证数据
    persistAuthorization: true
  info:
    # æ ‡é¢˜
    title: '标题:${ruoyi.name}多租户管理系统_接口文档'
@@ -225,14 +197,6 @@
        type: APIKEY
        in: HEADER
        name: ${sa-token.token-name}
springdoc:
  api-docs:
    # æ˜¯å¦å¼€å¯æŽ¥å£æ–‡æ¡£
    enabled: true
  swagger-ui:
    # æŒä¹…化认证数据
    persistAuthorization: true
  #这里定义了两个分组,可定义多个,也可以不定义
  group-configs:
    - group: 1.演示模块
ruoyi-common/ruoyi-common-core/pom.xml
@@ -34,6 +34,11 @@
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!--常用工具类 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java
@@ -2,16 +2,14 @@
import cn.hutool.core.util.ArrayUtil;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
/**
 * å¼‚步配置
@@ -22,16 +20,12 @@
@AutoConfiguration
public class AsyncConfig implements AsyncConfigurer {
    @Autowired
    @Qualifier("scheduledExecutorService")
    private ScheduledExecutorService scheduledExecutorService;
    /**
     * è‡ªå®šä¹‰ @Async æ³¨è§£ä½¿ç”¨ç³»ç»Ÿçº¿ç¨‹æ± 
     */
    @Override
    public Executor getAsyncExecutor() {
        return scheduledExecutorService;
        return SpringUtils.getBean("scheduledExecutorService");
    }
    /**
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java
@@ -22,18 +22,19 @@
     */
    @Bean
    public Validator validator(MessageSource messageSource) {
        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        // å›½é™…化
        factoryBean.setValidationMessageSource(messageSource);
        // è®¾ç½®ä½¿ç”¨ HibernateValidator æ ¡éªŒå™¨
        factoryBean.setProviderClass(HibernateValidator.class);
        Properties properties = new Properties();
        // è®¾ç½® å¿«é€Ÿå¼‚常返回
        properties.setProperty("hibernate.validator.fail_fast", "true");
        factoryBean.setValidationProperties(properties);
        // åŠ è½½é…ç½®
        factoryBean.afterPropertiesSet();
        return factoryBean.getValidator();
        try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) {
            // å›½é™…化
            factoryBean.setValidationMessageSource(messageSource);
            // è®¾ç½®ä½¿ç”¨ HibernateValidator æ ¡éªŒå™¨
            factoryBean.setProviderClass(HibernateValidator.class);
            Properties properties = new Properties();
            // è®¾ç½® å¿«é€Ÿå¼‚常返回
            properties.setProperty("hibernate.validator.fail_fast", "true");
            factoryBean.setValidationProperties(properties);
            // åŠ è½½é…ç½®
            factoryBean.afterPropertiesSet();
            return factoryBean.getValidator();
        }
    }
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
package org.dromara.common.core.factory;
import org.dromara.common.core.utils.StringUtils;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
import java.io.IOException;
/**
 * yml é…ç½®æºå·¥åŽ‚
 *
 * @author Lion Li
 */
public class YmlPropertySourceFactory extends DefaultPropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        String sourceName = resource.getResource().getFilename();
        if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) {
            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
            factory.setResources(resource.getResource());
            factory.afterPropertiesSet();
            return new PropertiesPropertySource(sourceName, factory.getObject());
        }
        return super.createPropertySource(name, resource);
    }
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java
@@ -3,6 +3,7 @@
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.i18n.LocaleContextHolder;
/**
@@ -23,6 +24,10 @@
     * @return èŽ·å–å›½é™…åŒ–ç¿»è¯‘å€¼
     */
    public static String message(String code, Object... args) {
        return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
        try {
            return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
        } catch (NoSuchMessageException e) {
            return code;
        }
    }
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
@@ -10,6 +10,7 @@
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@@ -19,6 +20,7 @@
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@@ -101,14 +103,22 @@
     * èŽ·å–request
     */
    public static HttpServletRequest getRequest() {
        return getRequestAttributes().getRequest();
        try {
            return getRequestAttributes().getRequest();
        } catch (Exception e) {
            return null;
        }
    }
    /**
     * èŽ·å–response
     */
    public static HttpServletResponse getResponse() {
        return getRequestAttributes().getResponse();
        try {
            return getRequestAttributes().getResponse();
        } catch (Exception e) {
            return null;
        }
    }
    /**
@@ -119,8 +129,33 @@
    }
    public static ServletRequestAttributes getRequestAttributes() {
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        return (ServletRequestAttributes) attributes;
        try {
            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
            return (ServletRequestAttributes) attributes;
        } catch (Exception e) {
            return null;
        }
    }
    public static String getHeader(HttpServletRequest request, String name) {
        String value = request.getHeader(name);
        if (StringUtils.isEmpty(value)) {
            return StringUtils.EMPTY;
        }
        return urlDecode(value);
    }
    public static Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> map = new LinkedCaseInsensitiveMap<>();
        Enumeration<String> enumeration = request.getHeaderNames();
        if (enumeration != null) {
            while (enumeration.hasMoreElements()) {
                String key = enumeration.nextElement();
                String value = request.getHeader(key);
                map.put(key, value);
            }
        }
        return map;
    }
    /**
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java
ÎļþÃû´Ó ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SwaggerConfig.java ÐÞ¸Ä
@@ -1,13 +1,13 @@
package org.dromara.common.doc.config;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.doc.config.properties.SwaggerProperties;
import org.dromara.common.doc.handler.OpenApiHandler;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.doc.config.properties.SpringDocProperties;
import org.dromara.common.doc.handler.OpenApiHandler;
import org.springdoc.core.configuration.SpringDocConfiguration;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
import org.springdoc.core.customizers.OpenApiCustomizer;
@@ -36,18 +36,18 @@
 */
@RequiredArgsConstructor
@AutoConfiguration(before = SpringDocConfiguration.class)
@EnableConfigurationProperties(SwaggerProperties.class)
@EnableConfigurationProperties(SpringDocProperties.class)
@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true)
public class SwaggerConfig {
public class SpringDocConfig {
    private final ServerProperties serverProperties;
    @Bean
    @ConditionalOnMissingBean(OpenAPI.class)
    public OpenAPI openApi(SwaggerProperties swaggerProperties) {
    public OpenAPI openApi(SpringDocProperties swaggerProperties) {
        OpenAPI openApi = new OpenAPI();
        // æ–‡æ¡£åŸºæœ¬ä¿¡æ¯
        SwaggerProperties.InfoProperties infoProperties = swaggerProperties.getInfo();
        SpringDocProperties.InfoProperties infoProperties = swaggerProperties.getInfo();
        Info info = convertInfo(infoProperties);
        openApi.info(info);
        // æ‰©å±•文档信息
@@ -65,7 +65,7 @@
        return openApi;
    }
    private Info convertInfo(SwaggerProperties.InfoProperties infoProperties) {
    private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) {
        Info info = new Info();
        info.setTitle(infoProperties.getTitle());
        info.setDescription(infoProperties.getDescription());
ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java
ÎļþÃû´Ó ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SwaggerProperties.java ÐÞ¸Ä
@@ -18,8 +18,8 @@
 * @author Lion Li
 */
@Data
@ConfigurationProperties(prefix = "swagger")
public class SwaggerProperties {
@ConfigurationProperties(prefix = "springdoc")
public class SpringDocProperties {
    /**
     * æ–‡æ¡£åŸºæœ¬ä¿¡æ¯
ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -1 +1 @@
org.dromara.common.doc.config.SwaggerConfig
org.dromara.common.doc.config.SpringDocConfig
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
@@ -7,11 +7,13 @@
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.dromara.common.core.factory.YmlPropertySourceFactory;
import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler;
import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
@@ -22,6 +24,7 @@
@EnableTransactionManagement(proxyTargetClass = true)
@AutoConfiguration
@MapperScan("${mybatis-plus.mapperPackage}")
@PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class)
public class MybatisPlusConfig {
    @Bean
ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
# å†…置配置 ä¸å…è®¸ä¿®æ”¹ å¦‚需修改请在 nacos ä¸Šå†™ç›¸åŒé…ç½®è¦†ç›–
# MyBatisPlus配置
# https://baomidou.com/config/
mybatis-plus:
  # å¯åŠ¨æ—¶æ˜¯å¦æ£€æŸ¥ MyBatis XML æ–‡ä»¶çš„存在,默认不检查
  checkConfigLocation: false
  configuration:
    # è‡ªåŠ¨é©¼å³°å‘½åè§„åˆ™ï¼ˆcamel case)映射
    mapUnderscoreToCamelCase: true
    # MyBatis è‡ªåŠ¨æ˜ å°„ç­–ç•¥
    # NONE:不启用 PARTIAL:只对非嵌套 resultMap è‡ªåŠ¨æ˜ å°„ FULL:对所有 resultMap è‡ªåŠ¨æ˜ å°„
    autoMappingBehavior: FULL
    # MyBatis è‡ªåŠ¨æ˜ å°„æ—¶æœªçŸ¥åˆ—æˆ–æœªçŸ¥å±žæ€§å¤„ç†ç­–
    # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
    autoMappingUnknownColumnBehavior: NONE
    # æ›´è¯¦ç»†çš„æ—¥å¿—输出 ä¼šæœ‰æ€§èƒ½æŸè€— org.apache.ibatis.logging.stdout.StdOutImpl
    # å…³é—­æ—¥å¿—记录 (可单纯使用 p6spy åˆ†æž) org.apache.ibatis.logging.nologging.NoLoggingImpl
    # é»˜è®¤æ—¥å¿—输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
    logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
  global-config:
    # æ˜¯å¦æ‰“印 Logo banner
    banner: true
    dbConfig:
      # ä¸»é”®ç±»åž‹
      # AUTO è‡ªå¢ž NONE ç©º INPUT ç”¨æˆ·è¾“å…¥ ASSIGN_ID é›ªèб ASSIGN_UUID å”¯ä¸€ UUID
      idType: ASSIGN_ID
      # é€»è¾‘已删除值(框架表均使用此值 ç¦æ­¢éšæ„ä¿®æ”¹)
      logicDeleteValue: 2
      # é€»è¾‘未删除值
      logicNotDeleteValue: 0
      insertStrategy: NOT_NULL
      updateStrategy: NOT_NULL
      whereStrategy: NOT_NULL
ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java
@@ -4,10 +4,12 @@
import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic;
import org.dromara.common.core.factory.YmlPropertySourceFactory;
import org.dromara.common.satoken.core.dao.PlusSaTokenDao;
import org.dromara.common.satoken.core.service.SaPermissionImpl;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
@@ -16,6 +18,7 @@
 * @author Lion Li
 */
@AutoConfiguration
@PropertySource(value = "classpath:common-satoken.yml", factory = YmlPropertySourceFactory.class)
public class SaTokenConfig implements WebMvcConfigurer {
    @Bean
ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
# å†…置配置 ä¸å…è®¸ä¿®æ”¹ å¦‚需修改请在 nacos ä¸Šå†™ç›¸åŒé…ç½®è¦†ç›–
# Sa-Token配置
sa-token:
  # å…è®¸ä»Ž è¯·æ±‚参数 è¯»å– token
  is-read-body: true
  # å…è®¸ä»Ž header è¯»å– token
  is-read-header: true
  # å…³é—­ cookie é‰´æƒ ä»Žæ ¹æºæœç» csrf æ¼æ´žé£Žé™©
  is-read-cookie: false
  # token前缀
  token-prefix: "Bearer"
ruoyi-common/ruoyi-common-sms/pom.xml
@@ -16,22 +16,19 @@
    </description>
    <dependencies>
        <dependency>
            <groupId>org.dromara</groupId>
            <artifactId>ruoyi-common-json</artifactId>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>dysmsapi20170525</artifactId>
            <optional>true</optional>
            <groupId>org.dromara.sms4j</groupId>
            <artifactId>sms4j-spring-boot-starter</artifactId>
            <exclusions>
                <!-- æŽ’除京东短信内存在的fastjson等待作者后续修复 -->
                <exclusion>
                    <groupId>com.alibaba</groupId>
                    <artifactId>fastjson</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.tencentcloudapi</groupId>
            <artifactId>tencentcloud-sdk-java-sms</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsConfig.java
@@ -1,15 +1,6 @@
package org.dromara.common.sms.config;
import org.dromara.common.sms.config.properties.SmsProperties;
import org.dromara.common.sms.core.AliyunSmsTemplate;
import org.dromara.common.sms.core.SmsTemplate;
import org.dromara.common.sms.core.TencentSmsTemplate;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * çŸ­ä¿¡é…ç½®ç±»
@@ -18,31 +9,7 @@
 * @version 4.2.0
 */
@AutoConfiguration
@EnableConfigurationProperties(SmsProperties.class)
//@EnableConfigurationProperties(SmsProperties.class)
public class SmsConfig {
    @Configuration
    @ConditionalOnProperty(value = "sms.enabled", havingValue = "true")
    @ConditionalOnClass(com.aliyun.dysmsapi20170525.Client.class)
    static class AliyunSmsConfig {
        @Bean
        public SmsTemplate aliyunSmsTemplate(SmsProperties smsProperties) {
            return new AliyunSmsTemplate(smsProperties);
        }
    }
    @Configuration
    @ConditionalOnProperty(value = "sms.enabled", havingValue = "true")
    @ConditionalOnClass(com.tencentcloudapi.sms.v20190711.SmsClient.class)
    static class TencentSmsConfig {
        @Bean
        public SmsTemplate tencentSmsTemplate(SmsProperties smsProperties) {
            return new TencentSmsTemplate(smsProperties);
        }
    }
}
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java
@@ -1,45 +1,19 @@
package org.dromara.common.sms.config.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
 * SMS短信 é…ç½®å±žæ€§
 *
 * @author Lion Li
 * @version 4.2.0
 */
@Data
@ConfigurationProperties(prefix = "sms")
public class SmsProperties {
    private Boolean enabled;
    /**
     * é…ç½®èŠ‚ç‚¹
     * é˜¿é‡Œäº‘ dysmsapi.aliyuncs.com
     * è…¾è®¯äº‘ sms.tencentcloudapi.com
     */
    private String endpoint;
    /**
     * key
     */
    private String accessKeyId;
    /**
     * å¯†åŒ™
     */
    private String accessKeySecret;
    /*
     * çŸ­ä¿¡ç­¾å
     */
    private String signName;
    /**
     * çŸ­ä¿¡åº”用ID (腾讯专属)
     */
    private String sdkAppId;
}
//package org.dromara.common.sms.config.properties;
//
//import lombok.Data;
//import org.springframework.boot.context.properties.ConfigurationProperties;
//
///**
// * SMS短信 é…ç½®å±žæ€§
// *
// * @author Lion Li
// * @version 4.2.0
// */
//@Data
//@ConfigurationProperties(prefix = "sms")
//public class SmsProperties {
//
//    private Boolean enabled;
//
//
//}
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/AliyunSmsTemplate.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/SmsTemplate.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/TencentSmsTemplate.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/entity/SmsResult.java
ÎļþÒÑɾ³ý
ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/exception/SmsException.java
ÎļþÒÑɾ³ý
ruoyi-modules/ruoyi-demo/pom.xml
@@ -97,16 +97,6 @@
            <groupId>org.dromara</groupId>
            <artifactId>ruoyi-common-websocket</artifactId>
        </dependency>
        <!-- çŸ­ä¿¡ ç”¨å“ªä¸ªå¯¼å…¥å“ªä¸ªä¾èµ– -->
<!--        <dependency>-->
<!--            <groupId>com.aliyun</groupId>-->
<!--            <artifactId>dysmsapi20170525</artifactId>-->
<!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>com.tencentcloudapi</groupId>-->
<!--            <artifactId>tencentcloud-sdk-java-sms</artifactId>-->
<!--        </dependency>-->
    </dependencies>
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java
@@ -1,17 +1,17 @@
package org.dromara.demo.controller;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.sms.config.properties.SmsProperties;
import org.dromara.common.sms.core.SmsTemplate;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.dromara.sms4j.provider.enumerate.SupplierType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedHashMap;
/**
 * çŸ­ä¿¡æ¼”示案例
@@ -26,10 +26,6 @@
@RequestMapping("/demo/sms")
public class SmsController {
    private final SmsProperties smsProperties;
//    private final SmsTemplate smsTemplate; // å¯ä»¥ä½¿ç”¨spring注入
//    private final AliyunSmsTemplate smsTemplate; // ä¹Ÿå¯ä»¥æ³¨å…¥æŸä¸ªåŽ‚å®¶çš„æ¨¡æ¿å·¥å…·
    /**
     * å‘送短信Aliyun
     *
@@ -38,17 +34,11 @@
     */
    @GetMapping("/sendAliyun")
    public R<Object> sendAliyun(String phones, String templateId) {
        if (!smsProperties.getEnabled()) {
            return R.fail("当前系统没有开启短信功能!");
        }
        if (!SpringUtils.containsBean("aliyunSmsTemplate")) {
            return R.fail("阿里云依赖未引入!");
        }
        SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class);
        Map<String, String> map = new HashMap<>(1);
        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
        map.put("code", "1234");
        Object send = smsTemplate.send(phones, templateId, map);
        return R.ok(send);
        SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
        SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
        return R.ok(smsResponse);
    }
    /**
@@ -59,18 +49,12 @@
     */
    @GetMapping("/sendTencent")
    public R<Object> sendTencent(String phones, String templateId) {
        if (!smsProperties.getEnabled()) {
            return R.fail("当前系统没有开启短信功能!");
        }
        if (!SpringUtils.containsBean("tencentSmsTemplate")) {
            return R.fail("腾讯云依赖未引入!");
        }
        SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class);
        Map<String, String> map = new HashMap<>(1);
        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
//        map.put("2", "测试测试");
        map.put("1", "1234");
        Object send = smsTemplate.send(phones, templateId, map);
        return R.ok(send);
        SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.TENCENT);
        SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
        return R.ok(smsResponse);
    }
}
ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java
@@ -2,6 +2,7 @@
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.generator.domain.GenTableColumn;
@@ -22,6 +23,6 @@
     * @return åˆ—信息
     */
    @DS("#dataName")
    List<GenTableColumn> selectDbTableColumnsByName(String tableName, String dataName);
    List<GenTableColumn> selectDbTableColumnsByName(@Param("tableName") String tableName, String dataName);
}
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
@@ -4,6 +4,7 @@
import cn.dev33.satoken.annotation.SaCheckRole;
import com.baomidou.lock.annotation.Lock4j;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
@@ -174,7 +175,8 @@
    @SaCheckPermission("system:tenant:edit")
    @Log(title = "租户", businessType = BusinessType.UPDATE)
    @GetMapping("/syncTenantPackage")
    public R<Void> syncTenantPackage(@NotBlank(message = "租户ID不能为空") String tenantId, @NotBlank(message = "套餐ID不能为空") Long packageId) {
    public R<Void> syncTenantPackage(@NotBlank(message = "租户ID不能为空") String tenantId,
                                     @NotNull(message = "套餐ID不能为空") Long packageId) {
        return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId)));
    }
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
@@ -94,7 +94,7 @@
     * @return ç”¨æˆ·å¯¹è±¡ä¿¡æ¯
     */
    @InterceptorIgnore(tenantLine = "true")
    SysUserVo selectTenantUserByUserName(String userName, String tenantId);
    SysUserVo selectTenantUserByUserName(@Param("userName") String userName, @Param("tenantId") String tenantId);
    /**
     * é€šè¿‡æ‰‹æœºå·æŸ¥è¯¢ç”¨æˆ·(不走租户插件)
@@ -104,7 +104,7 @@
     * @return ç”¨æˆ·å¯¹è±¡ä¿¡æ¯
     */
    @InterceptorIgnore(tenantLine = "true")
    SysUserVo selectTenantUserByPhonenumber(String phonenumber, String tenantId);
    SysUserVo selectTenantUserByPhonenumber(@Param("phonenumber") String phonenumber, @Param("tenantId") String tenantId);
    /**
     * é€šè¿‡é‚®ç®±æŸ¥è¯¢ç”¨æˆ·(不走租户插件)
@@ -114,7 +114,8 @@
     * @return ç”¨æˆ·å¯¹è±¡ä¿¡æ¯
     */
    @InterceptorIgnore(tenantLine = "true")
    SysUserVo selectTenantUserByEmail(String email, String tenantId);
    SysUserVo selectTenantUserByEmail(@Param("email") String email, @Param("tenantId") String tenantId);
    /**
     * é€šè¿‡ç”¨æˆ·ID查询用户
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java
@@ -22,7 +22,7 @@
    @Override
    public boolean isSensitive() {
        if (TenantHelper.isEnable()) {
            return !LoginHelper.isSuperAdmin() || !LoginHelper.isTenantAdmin();
            return !LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin();
        }
        return !LoginHelper.isSuperAdmin();
    }