diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/IgnoreAuth.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/IgnoreAuth.java new file mode 100644 index 0000000000..15a6de792f --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/IgnoreAuth.java @@ -0,0 +1,16 @@ +package org.jeecg.config.shiro; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 免认证注解,认证系统结合spring MVC的@RequestMapping获取请求路径进行免登录配置 + * @author eightmonth@qq.com + * @date 2024/2/28 9:58 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface IgnoreAuth { +} diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java b/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java index 8a4d959a0c..509614c994 100644 --- a/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java @@ -1,5 +1,6 @@ package org.jeecg.config.shiro; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; @@ -15,8 +16,11 @@ import org.jeecg.config.JeecgBaseConfig; import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean; import org.jeecg.config.shiro.filters.JwtFilter; +import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -26,6 +30,7 @@ import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; import org.springframework.web.filter.DelegatingFilterProxy; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; @@ -33,6 +38,8 @@ import javax.annotation.Resource; import javax.servlet.DispatcherType; import javax.servlet.Filter; +import java.lang.reflect.Method; +import java.time.Duration; import java.util.*; /** @@ -53,7 +60,9 @@ public class ShiroConfig { private JeecgBaseConfig jeecgBaseConfig; @Autowired(required = false) private RedisProperties redisProperties; - + + @Autowired + private ApplicationContext ctx; /** * Filter Chain定义说明 * @@ -168,6 +177,14 @@ public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { // 企业微信证书排除 filterChainDefinitionMap.put("/WW_verify*", "anon"); + // 通过注解免登录url + List ignoreAuthUrlList = collectIgnoreAuthUrl(ctx); + if (!CollectionUtils.isEmpty(ignoreAuthUrlList)) { + for (String url : ignoreAuthUrlList) { + filterChainDefinitionMap.put(url, "anon"); + } + } + // 添加自己的过滤器并且取名为jwt Map filterMap = new HashMap(1); //如果cloudServer为空 则说明是单体 需要加载跨域配置【微服务跨域切换】 @@ -320,4 +337,67 @@ public IRedisManager redisManager() { return manager; } + + @SneakyThrows + public List collectIgnoreAuthUrl(ApplicationContext context) { + List ignoreAuthUrls = new ArrayList<>(); + Map controllers = context.getBeansWithAnnotation(RestController.class); + for (Object bean : controllers.values()) { + if (!(bean instanceof Advised)) { + continue; + } + Class beanClass = ((Advised) bean).getTargetSource().getTarget().getClass(); + RequestMapping base = beanClass.getAnnotation(RequestMapping.class); + String[] baseUrl = {}; + if (Objects.nonNull(base)) { + baseUrl = base.value(); + } + Method[] methods = beanClass.getDeclaredMethods(); + + for (Method method : methods) { + if (method.isAnnotationPresent(IgnoreAuth.class) && method.isAnnotationPresent(RequestMapping.class)) { + RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); + String[] uri = requestMapping.value(); + ignoreAuthUrls.addAll(rebuildUrl(baseUrl, uri)); + } else if (method.isAnnotationPresent(IgnoreAuth.class) && method.isAnnotationPresent(GetMapping.class)) { + GetMapping requestMapping = method.getAnnotation(GetMapping.class); + String[] uri = requestMapping.value(); + ignoreAuthUrls.addAll(rebuildUrl(baseUrl, uri)); + } else if (method.isAnnotationPresent(IgnoreAuth.class) && method.isAnnotationPresent(PostMapping.class)) { + PostMapping requestMapping = method.getAnnotation(PostMapping.class); + String[] uri = requestMapping.value(); + ignoreAuthUrls.addAll(rebuildUrl(baseUrl, uri)); + } else if (method.isAnnotationPresent(IgnoreAuth.class) && method.isAnnotationPresent(PutMapping.class)) { + PutMapping requestMapping = method.getAnnotation(PutMapping.class); + String[] uri = requestMapping.value(); + ignoreAuthUrls.addAll(rebuildUrl(baseUrl, uri)); + } else if (method.isAnnotationPresent(IgnoreAuth.class) && method.isAnnotationPresent(DeleteMapping.class)) { + DeleteMapping requestMapping = method.getAnnotation(DeleteMapping.class); + String[] uri = requestMapping.value(); + ignoreAuthUrls.addAll(rebuildUrl(baseUrl, uri)); + } else if (method.isAnnotationPresent(IgnoreAuth.class) && method.isAnnotationPresent(PatchMapping.class)) { + PatchMapping requestMapping = method.getAnnotation(PatchMapping.class); + String[] uri = requestMapping.value(); + ignoreAuthUrls.addAll(rebuildUrl(baseUrl, uri)); + } + } + } + + return ignoreAuthUrls; + } + + private List rebuildUrl(String[] bases, String[] uris) { + List urls = new ArrayList<>(); + for (String base : bases) { + for (String uri : uris) { + urls.add(prefix(base)+prefix(uri)); + } + } + return urls; + } + + private String prefix(String seg) { + return seg.startsWith("/") ? seg : "/"+seg; + } + }