Spring安全请求带有hasAnyAuthority或hasAnyRole的Matchers无法按预期工作

bzzcjhmw  于 2023-08-04  发布在  Spring
关注(0)|答案(2)|浏览(155)

在我的Sping Boot 应用程序中,我使用的是pom.xml中的以下版本。Java版本17

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.4</version>
    <relativePath/> 
</parent>

字符串
我的控制器类,

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/common")
public class CommonController {

  @GetMapping("/dashboard")
  @PreAuthorize("hasRole('ROLE_MODERATOR') or hasRole('ROLE_ADMIN')")
  public String userAccess() {
    return "Dash Board Sample.";
  }
}


虽然我在方法级别使用@PreAuthorize,但我希望限制对url模式**/API/common/* 的访问,以仅允许具有角色“ROLE_USER”或“ROLE_MODERATOR”或“ROLE_ADMIN”的用户。但它不工作,并给我401时,使用hasAnyAuthority或hasAnyRole在过滤器链。
下面是我的整个SecurityConfig类,我使用的过滤器链如下所示。

import com.example.authservicedemo.security.jwt.AuthTokenFilter;
import com.example.authservicedemo.security.services.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig {

    @Value("${spring.security.debug:false}")
    boolean securityDebug;

    @Autowired
    UserDetailsServiceImpl userDetailsService;

    @Bean
    public AuthTokenFilter authenticationJwtTokenFilter() {
        return new AuthTokenFilter();
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
                .authorizeHttpRequests()
                .requestMatchers("/login/**")
                .anonymous()
                .requestMatchers("/api/auth/**").permitAll()
                .requestMatchers("/api/test/**").permitAll()
                //.requestMatchers("/api/common/**").permitAll()
                .requestMatchers("/api/common/**").hasAnyAuthority("ROLE_USER", "ROLE_MODERATOR", "ROLE_ADMIN")
                 //.requestMatchers("/api/common/**") .hasAnyRole("USER", "MODERATOR", "ADMIN")
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        return http.build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.debug(securityDebug)
                .ignoring()
                .requestMatchers("/css/**", "/js/**", "/img/**", "/lib/**", "/favicon.ico");
    }
}


但是当我访问API时,它给了我401错误。

curl --location 'http://localhost:8080/api/common/dashboard' \
--header 'Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY5MTAzNDk4OSwiZXhwIjoxNjkxMTIxMzg5LCJyb2xlcyI6WyJQXzEiLCJQXzMiLCJBXzEiLCJBXzIiLCJBXzMiLCJBXzQiLCJBXzUiLCJST0xFX0FETUlOIl19.8Fp6OPBMsredmLEi2RdB0Bkg0Oa1S_k869mx25CJxEjD01ePys7J7E7mWHRmeeKFMX_ybeDpdK_5loT26eBMAQ'


当我取消注解行**.requestMatchers(“/API/common/**”).permitAll()**时,这与方法级别的security @PreAuthorize配合得很好。那么,如何限制具有特定角色的用户对特定URL模式的访问?
我不知道我做错了什么。你的回应将是真正的赞赏。

qeeaahzv

qeeaahzv1#

您同时使用方法级安全注解(@PreAuthorize)和基于URL的安全规则。如果您使用的是方法级安全性(@preAuthorize),则安全检查将基于注解中指定的表达式执行,并且SecurityConfig中定义的基于URL的安全规则可能对这些方法没有任何影响。
此外,建议在服务层中应用方法级安全性。Spring安全文档
对于您的安全配置,请尝试使用antmatchers,如下所示:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable()
            .authorizeRequests()
            .antMatchers("/login/**").anonymous()
            .antMatchers("/api/auth/**").permitAll()
            .antMatchers("/api/test/**").permitAll()
            .antMatchers("/api/common/**").hasAnyAuthority("ROLE_USER", "ROLE_MODERATOR", "ROLE_ADMIN")
            .anyRequest().authenticated()
            .and()
            .httpBasic()
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    return http.build();
}

字符串

kqlmhetl

kqlmhetl2#

这不是对您问题的完整回答,但请检查我的配置。此外,您还可以同时拥有端点安全性和方法级安全性,这不是问题。

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
    
        http
            .userDetailsService(jpaUserDetailsService)
            .authorizeHttpRequests(auth -> auth
                            .requestMatchers("/h2-console/**").permitAll()
                            .requestMatchers( "/auth/**").permitAll()
                            .requestMatchers(HttpMethod.POST, 
                                "/auth/**").permitAll()
                            .anyRequest().authenticated()
            )
            .csrf(AbstractHttpConfigurer::disable) //to be able to use h2- 
                //console and different domains with the login
            .cors(cors -> cors.configurationSource(corsConfigurationSource()))
            .formLogin(Customizer.withDefaults())
            .logout(logout -> logout
                .logoutUrl("/logout")
                .invalidateHttpSession(true)
                .logoutSuccessUrl("/auth/login")
            )
            .headers(headers -> headers 
                 .frameOptions(FrameOptionsConfig::disable)) //to be able to use 
                   //h2-console
            .sessionManagement((sessionManagement) -> sessionManagement
                 .sessionConcurrency((sessionConcurrency) ->
                     sessionConcurrency
                         //.maximumSessions(1)
                         //.maxSessionsPreventsLogin(true)
                         .expiredUrl("/auth/login?invalid-session=true")
                         .sessionRegistry(sessionRegistry())
                 )
                 // Set the custom session repository here
                 //.sessionRepository(customSessionRepository()) // Inject your 
                    //custom session repository
            );

            //http.authenticationProvider(authProvider());
            
    return  http.build();
}

字符串
下面是一个示例,如果您希望基于角色保护端点,最好在类中使用它:

@RestController
@RequestMapping("/manage-users")
@PreAuthorize("hasAuthority('ADMIN')")
public class UsersController{
     //some code
}


对于方法级别:

@GetMapping("/new")
@PreAuthorize("hasAuthority('ADMIN')")
public String showRegistrationForm() {
    return "registrationForm";
}

相关问题