【问题标题】:Spring MVC webapp + REST: Authorization issueSpring MVC webapp + REST:授权问题
【发布时间】:2020-08-13 17:18:48
【问题描述】:

我正在使用 Spring MVC 构建一个 CRM 系统。现在我正在为系统添加 REST 支持,但 Spring Security 出于某种原因将允许未经授权的具有“EMPLOYEE”角色的用户访问 POST 方法(在系统中创建新客户)。 一切都适用于表单和身份验证。只是授权因某种原因而失败,专门针对 RestController。

我正在使用 PostgreSQL 来存储客户和用户以及进行身份验证。

注意:我将“/customer”用于 REST 并作为 webapp 表单的入口点。

这是我的安全配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers(HttpMethod.GET, "/customer").hasRole("EMPLOYEE")
            .antMatchers(HttpMethod.POST, "/customer").hasAnyRole("MANAGER", "ADMIN")
            .antMatchers("/customer/showForm*").hasAnyRole("MANAGER", "ADMIN")
            .antMatchers("/customer/save*").hasAnyRole("MANAGER", "ADMIN")
            .antMatchers("/customer/delete").hasRole("ADMIN")
            .antMatchers("/customer/**").hasRole("EMPLOYEE")
            .antMatchers("/resources/**").permitAll()
            .and()
            .httpBasic()
            .and()
            .formLogin()
            .loginPage("/login")
            .loginProcessingUrl("/authenticate")
            .permitAll()
            .and()
            .logout().permitAll()
            .and()
            .exceptionHandling().accessDeniedPage("/access-denied")
            .and()
            .csrf().disable();
    }

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

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

这是我的 RestController:

@RestController
@RequestMapping("/customer")
public class CustomerRestController {

    @Autowired
    private CustomerService customerService;

    @GetMapping
    public List<Customer> getCustomers() {
        return customerService.getCustomers();
    }

    @GetMapping("/{customerId}")
    public Customer getCustomer(@PathVariable int customerId) {
        Customer customer = customerService.getCustomer(customerId);
        if (customer == null) throw new CustomerNotFoundException("Customer not found: id = " + customerId);
        return customer;
    }

    @PostMapping
    public Customer addCustomer(@RequestBody Customer customer) {
        customer.setId(0);
        customerService.saveCustomer(customer);
        return customer;
    }
}

更新:

  1. 我尝试将 RestController 映射到另一个路径 - 没有成功。
  2. 我还尝试将 SecurityConfig 拆分为多个入口点 - 不起作用,并且由于某种原因还开始自动登录。
  3. 在 RestController 中的 Post 方法之前添加了 @Secured({"ROLE_MANAGER", "ROLE_ADMIN"}) - 结果相同。

似乎我的 RestController Spring 根本不关心用户的角色。

【问题讨论】:

    标签: spring-mvc spring-security spring-rest


    【解决方案1】:

    经过数小时的研究和反复试验,一切正常。 关键问题是方法路径中缺少星号。而不是“/customer”,它必须是“/customer/**”。 我还稍微改变了 Web 表单和 REST 支持的路径,以避免混淆并使支持更容易。 无论如何,这里是更新的 SecurityConfig:

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private UserService userService;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(authenticationProvider());
        }
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Bean
        public DaoAuthenticationProvider authenticationProvider() {
            DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
            auth.setUserDetailsService(userService);
            auth.setPasswordEncoder(passwordEncoder());
            return auth;
        }
    
        @Configuration
        @Order(1)
        public static class ApiSecurityConfig extends WebSecurityConfigurerAdapter {
    
            @Bean
            public AuthenticationEntryPoint entryPoint() {
                return new CustomAuthenticationEntryPoint();
            }
    
            @Bean
            public AccessDeniedHandler accessDeniedHandler() {
                return new CustomAccessDeniedHandler();
            }
    
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http.csrf().disable().antMatcher("/api/**")
                    .authorizeRequests()
                    .antMatchers(HttpMethod.GET, "/api/customers/**").hasRole("EMPLOYEE")
                    .antMatchers(HttpMethod.POST, "/api/customers/**").hasAnyRole("MANAGER", "ADMIN")
                    .and()
                    .httpBasic()
                    .authenticationEntryPoint(entryPoint())
                    .and()
                    .exceptionHandling().accessDeniedHandler(accessDeniedHandler())
                    .and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            }
        }
    
        @Configuration
        @Order(2)
        public static class FormSecurityConfig extends WebSecurityConfigurerAdapter {
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http.authorizeRequests()
                    .antMatchers("/customer/showForm*").hasAnyRole("MANAGER", "ADMIN")
                    .antMatchers("/customer/save*").hasAnyRole("MANAGER", "ADMIN")
                    .antMatchers("/customer/delete").hasRole("ADMIN")
                    .antMatchers("/customer/**").hasRole("EMPLOYEE")
                    .antMatchers("/resources/**").permitAll()
                    .and()
                    .formLogin()
                    .loginPage("/login")
                    .loginProcessingUrl("/authenticate")
                    .permitAll()
                    .and()
                    .logout().permitAll()
                    .and()
                    .exceptionHandling().accessDeniedPage("/access-denied");
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-14
      • 2013-03-15
      • 2018-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多