Эх сурвалжийг харах

Merge remote-tracking branch 'upstream/master'

“zyj” 3 жил өмнө
parent
commit
9912c85abb

+ 1 - 1
pom.xml

@@ -42,7 +42,7 @@
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-dependencies</artifactId>
-                <version>2.5.13</version>
+                <version>2.5.14</version>
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>

+ 19 - 0
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java

@@ -0,0 +1,19 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 匿名访问不鉴权注解
+ * 
+ * @author ruoyi
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Anonymous
+{
+}

+ 0 - 4
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java

@@ -5,8 +5,6 @@ import java.util.List;
 import javax.validation.constraints.*;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.annotation.Excel.ColumnType;
 import com.ruoyi.common.annotation.Excel.Type;
@@ -202,8 +200,6 @@ public class SysUser extends BaseEntity
         this.avatar = avatar;
     }
 
-    @JsonIgnore
-    @JsonProperty
     public String getPassword()
     {
         return password;

+ 19 - 15
ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java

@@ -2,6 +2,7 @@ package com.ruoyi.common.utils;
 
 import java.util.Collection;
 import java.util.List;
+import com.alibaba.fastjson2.JSONArray;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.domain.entity.SysDictData;
 import com.ruoyi.common.core.redis.RedisCache;
@@ -38,10 +39,10 @@ public class DictUtils
      */
     public static List<SysDictData> getDictCache(String key)
     {
-        Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
-        if (StringUtils.isNotNull(cacheObj))
+        JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
+        if (StringUtils.isNotNull(arrayCache))
         {
-            return StringUtils.cast(cacheObj);
+            return arrayCache.toList(SysDictData.class);
         }
         return null;
     }
@@ -83,27 +84,30 @@ public class DictUtils
         StringBuilder propertyString = new StringBuilder();
         List<SysDictData> datas = getDictCache(dictType);
 
-        if (StringUtils.containsAny(separator, dictValue) && StringUtils.isNotEmpty(datas))
+        if (StringUtils.isNotNull(datas))
         {
-            for (SysDictData dict : datas)
+            if (StringUtils.containsAny(separator, dictValue))
             {
-                for (String value : dictValue.split(separator))
+                for (SysDictData dict : datas)
                 {
-                    if (value.equals(dict.getDictValue()))
+                    for (String value : dictValue.split(separator))
                     {
-                        propertyString.append(dict.getDictLabel()).append(separator);
-                        break;
+                        if (value.equals(dict.getDictValue()))
+                        {
+                            propertyString.append(dict.getDictLabel()).append(separator);
+                            break;
+                        }
                     }
                 }
             }
-        }
-        else
-        {
-            for (SysDictData dict : datas)
+            else
             {
-                if (dictValue.equals(dict.getDictValue()))
+                for (SysDictData dict : datas)
                 {
-                    return dict.getDictLabel();
+                    if (dictValue.equals(dict.getDictValue()))
+                    {
+                        return dict.getDictLabel();
+                    }
                 }
             }
         }

+ 0 - 18
ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java

@@ -3,13 +3,9 @@ package com.ruoyi.framework.config;
 import java.nio.charset.Charset;
 import org.springframework.data.redis.serializer.RedisSerializer;
 import org.springframework.data.redis.serializer.SerializationException;
-import org.springframework.util.Assert;
 import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONReader;
 import com.alibaba.fastjson2.JSONWriter;
-import com.fasterxml.jackson.databind.JavaType;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.type.TypeFactory;
 
 /**
  * Redis使用FastJson序列化
@@ -18,9 +14,6 @@ import com.fasterxml.jackson.databind.type.TypeFactory;
  */
 public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
 {
-    @SuppressWarnings("unused")
-    private ObjectMapper objectMapper = new ObjectMapper();
-
     public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
 
     private Class<T> clazz;
@@ -52,15 +45,4 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
 
         return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);
     }
-
-    public void setObjectMapper(ObjectMapper objectMapper)
-    {
-        Assert.notNull(objectMapper, "'objectMapper' must not be null");
-        this.objectMapper = objectMapper;
-    }
-
-    protected JavaType getJavaType(Class<?> clazz)
-    {
-        return TypeFactory.defaultInstance().constructType(clazz);
-    }
 }

+ 0 - 10
ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java

@@ -8,11 +8,6 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.fasterxml.jackson.annotation.PropertyAccessor;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
 
 /**
  * redis配置
@@ -32,11 +27,6 @@ public class RedisConfig extends CachingConfigurerSupport
 
         FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
 
-        ObjectMapper mapper = new ObjectMapper();
-        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
-        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
-        serializer.setObjectMapper(mapper);
-
         // 使用StringRedisSerializer来序列化和反序列化redis的key值
         template.setKeySerializer(new StringRedisSerializer());
         template.setValueSerializer(serializer);

+ 17 - 15
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java

@@ -8,12 +8,14 @@ import org.springframework.security.config.annotation.authentication.builders.Au
 import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
 import org.springframework.security.config.http.SessionCreationPolicy;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 import org.springframework.security.web.authentication.logout.LogoutFilter;
 import org.springframework.web.filter.CorsFilter;
+import com.ruoyi.framework.config.properties.PermitAllUrlProperties;
 import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
 import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;
 import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;
@@ -55,7 +57,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
      */
     @Autowired
     private CorsFilter corsFilter;
-    
+
+    /**
+     * 允许匿名访问的地址
+     */
+    @Autowired
+    private PermitAllUrlProperties permitAllUrl;
+
     /**
      * 解决 无法直接注入 AuthenticationManager
      *
@@ -87,6 +95,10 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
     @Override
     protected void configure(HttpSecurity httpSecurity) throws Exception
     {
+        // 注解标记允许匿名访问的url
+        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();
+        permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());
+
         httpSecurity
                 // CSRF禁用,因为不使用session
                 .csrf().disable()
@@ -98,24 +110,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 .authorizeRequests()
                 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                 .antMatchers("/login", "/register", "/captchaImage").anonymous()
-                .antMatchers(
-                        HttpMethod.GET,
-                        "/",
-                        "/*.html",
-                        "/**/*.html",
-                        "/**/*.css",
-                        "/**/*.js",
-                        "/profile/**"
-                ).permitAll()
-                .antMatchers("/swagger-ui.html").anonymous()
-                .antMatchers("/swagger-resources/**").anonymous()
-                .antMatchers("/webjars/**").anonymous()
-                .antMatchers("/*/api-docs").anonymous()
-                .antMatchers("/druid/**").anonymous()
+                // 静态资源,可匿名访问
+                .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
+                .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
                 // 除上面外的所有请求全部需要鉴权认证
                 .anyRequest().authenticated()
                 .and()
                 .headers().frameOptions().disable();
+        // 添加Logout filter
         httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
         // 添加JWT filter
         httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

+ 72 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java

@@ -0,0 +1,72 @@
+package com.ruoyi.framework.config.properties;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.regex.Pattern;
+import org.apache.commons.lang3.RegExUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+import com.ruoyi.common.annotation.Anonymous;
+
+/**
+ * 设置Anonymous注解允许匿名访问的url
+ * 
+ * @author ruoyi
+ */
+@Configuration
+public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware
+{
+    private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
+
+    private ApplicationContext applicationContext;
+
+    private List<String> urls = new ArrayList<>();
+
+    public String ASTERISK = "*";
+
+    @Override
+    public void afterPropertiesSet()
+    {
+        RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
+        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
+
+        map.keySet().forEach(info -> {
+            HandlerMethod handlerMethod = map.get(info);
+
+            // 获取方法上边的注解 替代path variable 为 *
+            Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);
+            Optional.ofNullable(method).ifPresent(anonymous -> info.getPatternsCondition().getPatterns()
+                    .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
+
+            // 获取类上边的注解, 替代path variable 为 *
+            Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class);
+            Optional.ofNullable(controller).ifPresent(anonymous -> info.getPatternsCondition().getPatterns()
+                    .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
+        });
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext context) throws BeansException
+    {
+        this.applicationContext = context;
+    }
+
+    public List<String> getUrls()
+    {
+        return urls;
+    }
+
+    public void setUrls(List<String> urls)
+    {
+        this.urls = urls;
+    }
+}

+ 1 - 1
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml

@@ -57,7 +57,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </sql>
     
     <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
-		select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
+		select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
 		left join sys_dept d on u.dept_id = d.dept_id
 		where u.del_flag = '0'
 		<if test="userId != null and userId != 0">

+ 1 - 1
ruoyi-ui/src/utils/dict/DictMeta.js

@@ -11,7 +11,7 @@ import DictOptions from './DictOptions'
 export default class DictMeta {
   constructor(options) {
     this.type = options.type
-    this.request = options.request,
+    this.request = options.request
     this.responseConverter = options.responseConverter
     this.labelField = options.labelField
     this.valueField = options.valueField

+ 4 - 4
ruoyi-ui/src/utils/ruoyi.js

@@ -68,7 +68,7 @@ export function addDateRange(params, dateRange, propName) {
   return search;
 }
 
-// 回显数据字典 
+// 回显数据字典
 export function selectDictLabel(datas, value) {
   if (value === undefined) {
     return "";
@@ -207,10 +207,10 @@ export function tansParams(params) {
   for (const propName of Object.keys(params)) {
     const value = params[propName];
     var part = encodeURIComponent(propName) + "=";
-    if (value !== null && typeof (value) !== "undefined") {
+    if (value !== null && value !== "" && typeof (value) !== "undefined") {
       if (typeof value === 'object') {
         for (const key of Object.keys(value)) {
-          if (value[key] !== null && typeof (value[key]) !== 'undefined') {
+          if (value[key] !== null && value !== "" && typeof (value[key]) !== 'undefined') {
             let params = propName + '[' + key + ']';
             var subPart = encodeURIComponent(params) + "=";
             result += subPart + encodeURIComponent(value[key]) + "&";
@@ -233,4 +233,4 @@ export async function blobValidate(data) {
   } catch (error) {
     return true;
   }
-}
+}

+ 1 - 1
ruoyi-ui/src/views/tool/build/RightPanel.vue

@@ -486,7 +486,7 @@
             </el-tree>
           </template>
 
-          <template v-if="activeData.layout === 'colFormItem'">
+          <template v-if="activeData.layout === 'colFormItem' && activeData.tag !== 'el-button'">
             <el-divider>正则校验</el-divider>
             <div
               v-for="(item, index) in activeData.regList"