You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Spring Security未阻止USER角色的POST请求?

问题:普通USER角色用户可执行需ADMIN权限的POST请求

背景配置

  1. 用户权限配置
@Bean
public UserDetailsService uds() {
    UserDetails admin = User.builder()
        .username("admin")
        .password(encoder().encode("pwa"))
        .roles("ADMIN")
        .build();
    UserDetails user = User.builder()
        .username("user")
        .password(encoder().encode("pwu"))
        .roles("USER")
        .build();
    return new InMemoryUserDetailsManager(admin, user);
}
  1. Repository配置
@RepositoryRestResource
public interface CountryRepo extends CrudRepository<Country, Long> { }
  1. SecurityFilterChain配置
@Bean
SecurityFilterChain configureSecurityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(authCustomizer -> authCustomizer
            .requestMatchers("/api/countries").permitAll()
            .requestMatchers("/h2").permitAll()
            .requestMatchers(HttpMethod.POST, "/api/countries").hasRole("ADMIN")  // 预期仅ADMIN可访问
            .anyRequest().authenticated()
        )
        .csrf().disable()
        .httpBasic(withDefaults());
    http.headers().frameOptions().disable();
    return http.build();
}

问题现象

配置中明确要求POST /api/countries仅允许ADMIN角色访问,但实际测试中,拥有USER角色的user用户也能成功发起该POST请求并创建国家,未返回预期的401/403状态码。

原因分析

Spring Security的授权规则是按定义顺序匹配,优先执行第一个匹配的规则。

当前配置中,.requestMatchers("/api/countries").permitAll()这条规则会匹配所有HTTP方法的/api/countries请求(包括POST),并且直接允许所有访问。后面的.requestMatchers(HttpMethod.POST, "/api/countries").hasRole("ADMIN")规则因为前面的规则已经匹配成功,根本不会被执行。

解决办法

调整规则顺序,将更具体、权限要求更高的规则放在通用规则前面,或者给通用规则指定HTTP方法,避免覆盖后续的特定规则。

方案1:调整规则顺序,优先匹配POST请求

@Bean
SecurityFilterChain configureSecurityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(authCustomizer -> authCustomizer
            .requestMatchers("/h2").permitAll()
            // 先匹配POST请求的权限规则
            .requestMatchers(HttpMethod.POST, "/api/countries").hasRole("ADMIN")
            // 再允许GET请求的访问
            .requestMatchers(HttpMethod.GET, "/api/countries").permitAll()
            .anyRequest().authenticated()
        )
        .csrf().disable()
        .httpBasic(withDefaults());
    http.headers().frameOptions().disable();
    return http.build();
}

方案2:给通用规则指定HTTP方法

如果原本的/api/countries仅想开放GET访问,直接修改规则:

.requestMatchers(HttpMethod.GET, "/api/countries").permitAll()
.requestMatchers(HttpMethod.POST, "/api/countries").hasRole("ADMIN")

这样POST请求会匹配到对应的ADMIN权限规则,USER角色用户发起请求时会返回403状态码,符合预期。

内容的提问来源于stack exchange,提问作者TMOTTM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 13:15:24