Apache Shiro 正在破坏我的 Spring Boot Rest API 的 CORS 配置
Posted
技术标签:
【中文标题】Apache Shiro 正在破坏我的 Spring Boot Rest API 的 CORS 配置【英文标题】:Apache Shiro is breaking the CORS configuration of my Spring Boot RestAPI 【发布时间】:2020-07-02 08:05:08 【问题描述】:在修改了不同的安全框架之后,我决定在我的 Spring Boot RestAPI 中使用 Apache Shiro,因为它似乎提供了必要的灵活性而没有太多的官僚开销。到目前为止,除了将 maven 依赖项添加到我的项目之外,我什么都没做:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.5.1</version>
</dependency>
这迫使我定义一个 Realm bean 以启动应用程序:
@Bean
public Realm realm()
return new TMTRealm();
除了实现 Realm 接口之外,该 bean 几乎什么也没做:
public class TMTRealm implements Realm
private static final String Realm_Name = "realm_name";
@Override
public String getName()
return Realm_Name;
@Override
public boolean supports(AuthenticationToken token)
return false;
@Override
public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
return null;
到目前为止一切顺利。除了现在我的 RestAPI 违反了 CORS 政策,没有将“Access-Control-Allow-Origin”标头添加到其响应的任何中。我注意到 Chrome 没有发送任何专用的 OPTIONS 请求,而是发送了两个相同方法的请求,在这种情况下为 GET,第一个失败如下:
Access to XMLHttpRequest at 'http://localhost:8081/geo/country/names?typed=D&lang=en-US' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
在没有 Shiro 的情况下,它工作得非常好,无论是在控制器上使用 Spring 的 @CrossOrigin 注释的优雅方式,还是定义 CorsFilter bean 的蛮力“老派”方式:
@Bean
public CorsFilter corsFilter()
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Arrays.asList("*"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("OPTIONS", "GET", "POST", "PUT", "DELETE"));
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
我已经实现了 Spring 的 ApplicationListener 接口,以便在 ApplicationContext 启动时挂钩,因此可以看到 corsFilter bean 已注册并存在:
@Override
public void onApplicationEvent(ContextRefreshedEvent event)
System.out.println("############ - application context started with beans: ");
final String[] beans = event.getApplicationContext().getBeanDefinitionNames();
Arrays.parallelSort(beans);
for (final String bean : beans)
System.out.println(bean);
输出:
...
conditionEvaluationDeltaLoggingListener
conventionErrorViewResolver
corsFilter
countryController
...
但是过滤器永远不会被任何请求调用(我设置了一个断点和 System.out 来证明它)。我还注意到出现了三个 Shiro bean:
shiroEventBusAwareBeanPostProcessor
shiroFilterChainDefinition
shiroFilterFactoryBean
因此,我认为可能是 shiroFilterFactoryBean 以某种方式破坏了它,需要额外注意和配置。不幸的是,Apache Shiro 文档似乎没有说明跨域请求,我认为这不是(必然)Shiro 安全问题的一部分,而是底层的 Restful API,即 Spring。谷歌搜索这个问题也没有产生任何有用的结果,所以我怀疑我错过了一些大的东西,或者更糟糕的是,这里有一些小而明显的东西。虽然我正在尝试解决这个问题,但非常感谢任何帮助或提示,谢谢!
【问题讨论】:
【参考方案1】:噢,我想通了。我在 filter-servlet 领域已经有一段时间了,所以我没有想到过滤器的执行顺序。我这样做的天真方式,Shiro 过滤器链总是在我的自定义 CorsFilter 之前执行(显然也是 @CrossOrigin 注释的默认 Spring 处理器)。由于我还没有配置 Shiro,任何请求都将被拒绝,因为既没有经过身份验证也没有授权,因此从未执行 CorsFilter 导致没有 Access-Control-Allow-Origin 标头的响应。 p>
所以,要么我正确配置 Shiro,要么只是确保在 Shiro 过滤器之前执行 CorsFilter,方法是使用 Spring 的 FilterRegistrationBean 像这样(setOrder 为零):
@Configuration
public class RestApiConfig
@Bean
public FilterRegistrationBean<CorsFilter> corsFilterRegistrationBean()
final FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>(this.corsFilter());
registration.setOrder(0);
return registration;
private CorsFilter corsFilter()
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Arrays.asList("*"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("OPTIONS", "GET", "POST", "PUT", "DELETE"));
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
@Bean
public Realm realm()
return new TMTRealm();
编辑:
呃,其实我太容易注意到了。您所要做的就是配置一个 ShiroFilterChainDefinition bean,以便它引用控制器类或方法上的注释,如下所示:
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition()
final DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
chainDefinition.addPathDefinition("/**", "anon");
return chainDefinition;
就像documentation 中描述的一样。现在它可以与 CorsFilter bean 或 Spring 的 @CrossOrigin 注释一起使用。如果控制器方法上没有 Shiro 注解,则请求将被传递。
【讨论】:
以上是关于Apache Shiro 正在破坏我的 Spring Boot Rest API 的 CORS 配置的主要内容,如果未能解决你的问题,请参考以下文章
无法在自定义 Apache Shiro AuthorizingRealm 中 @Inject 我的 DAO
apache shiro 使用 Hashing Credentials 无法成功登录