diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java index 77b46d2c..5b852868 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java @@ -15,6 +15,7 @@ import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSource import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -23,6 +24,7 @@ import com.ruoyi.common.constant.Constants; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.security.CipherUtils; import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.framework.config.properties.PermitAllUrlProperties; import com.ruoyi.framework.shiro.realm.UserRealm; import com.ruoyi.framework.shiro.rememberMe.CustomCookieRememberMeManager; import com.ruoyi.framework.shiro.session.OnlineSessionDAO; @@ -143,6 +145,9 @@ public class ShiroConfig @Value("${csrf.whites: ''}") private String csrfWhites; + @Autowired + private PermitAllUrlProperties permitAllUrl; + /** * 缓存管理器 使用Ehcache实现 */ @@ -312,6 +317,8 @@ public class ShiroConfig filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/ruoyi/**", "anon"); filterChainDefinitionMap.put("/captcha/captchaImage**", "anon"); + // 匿名访问不鉴权注解列表 + permitAllUrl.getUrls().forEach(url -> filterChainDefinitionMap.put(url, "anon")); // 退出 logout地址,shiro去清除session filterChainDefinitionMap.put("/logout", "logout"); // 不需要拦截的访问 diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java new file mode 100644 index 00000000..02867f5c --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java @@ -0,0 +1,101 @@ +package com.ruoyi.framework.config.properties; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +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.beans.factory.config.BeanDefinition; +import org.springframework.boot.autoconfigure.AutoConfigurationPackages; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +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 static final String ASTERISK = "*"; + + private ApplicationContext applicationContext; + + private List urls = new ArrayList<>(); + + @Override + public void afterPropertiesSet() throws Exception + { + String basePackage = AutoConfigurationPackages.get(applicationContext.getAutowireCapableBeanFactory()).get(0); + + ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); + scanner.addIncludeFilter(new AnnotationTypeFilter(Controller.class)); + for (BeanDefinition bd : scanner.findCandidateComponents(basePackage)) + { + Class beanClass = Class.forName(bd.getBeanClassName()); + RequestMapping base = beanClass.getAnnotation(RequestMapping.class); + String[] baseUrl = base != null ? base.value() : new String[] {}; + boolean classAnonymous = beanClass.isAnnotationPresent(Anonymous.class); + for (Method method : beanClass.getDeclaredMethods()) + { + boolean methodAnonymous = method.isAnnotationPresent(Anonymous.class); + if (!classAnonymous && !methodAnonymous) + { + continue; + } + RequestMapping mapping = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class); + if (mapping != null && mapping.value().length > 0) + { + urls.addAll(rebuildUrl(baseUrl, mapping.value())); + } + } + } + } + + @Override + public void setApplicationContext(ApplicationContext context) throws BeansException + { + this.applicationContext = context; + } + + @SuppressWarnings("deprecation") + private List rebuildUrl(String[] bases, String[] uris) + { + List urls = new ArrayList<>(); + for (String base : bases) + { + for (String uri : uris) + { + urls.add(prefix(base) + prefix(RegExUtils.replaceAll(uri, PATTERN, ASTERISK))); + } + } + return urls; + } + + private String prefix(String seg) + { + return seg.startsWith("/") ? seg : "/" + seg; + } + + public List getUrls() + { + return urls; + } + + public void setUrls(List urls) + { + this.urls = urls; + } +}