【问题标题】:In Springboot Unit test, MockMvc returns 403 Forbidden在 Spring Boot 单元测试中,MockMvc 返回 403 Forbidden
【发布时间】:2020-11-13 16:37:57
【问题描述】:

在 Springboot 单元测试中总是返回 403 错误,我尝试了各种不同的配置,使用 AutoConfigureMockMvc 和安全错误,不包括安全自动配置得到 403 错误。谁能帮我解决这个问题。

这是我的安全实现

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource(name = "userService")
    private UserDetailsService userDetailsService;

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Autowired
    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationEventPublisher(authenticationEventPublisher())
                .userDetailsService(userDetailsService)
                .passwordEncoder(encoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf()
                .disable()
                .anonymous()
                .disable()
                .authorizeRequests()
                .antMatchers("/api-docs/**")
                .permitAll();
    }

    @Bean
    public DefaultAuthenticationEventPublisher authenticationEventPublisher() {
        return new DefaultAuthenticationEventPublisher();
    }

    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }

    @Bean
    public BCryptPasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(0);
        return bean;
    }
   }

共享Api实现类,新增PreAuthorize -Admin,查看所有用户

@RestController
@RequestMapping("/api/userInfo")
public class UserController {

    private final Logger LOG = Logger.getLogger(getClass());

    private String serviceMsg = "serviceMsg";

    @Autowired
    private UserService userService;

    @Autowired
    private UserServiceUtil util;

    
    @PreAuthorize("hasAnyRole('ADMIN')")
    @RequestMapping(method = RequestMethod.GET, produces = "application/json" )
    @ApiOperation(value = "Get details of all RA2 users in a paginated JSON format")
    public Page<User> listUser(Pageable pageable) {
        return userService.getUserSummary(pageable);
    }

这是我的 JUnit 测试,正在发送 get 请求并返回 403 错误。

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
@ContextConfiguration
@AutoConfigureMockMvc(addFilters = false)

public class UserControllerTest {
    
    @Configuration
    
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    protected static class TestConfiguration {
         @Bean
         @Primary
         public UserService getUserService(){
               return Mockito.mock(UserService.class);
         }
         
         @Bean
         @Primary
         public UserServiceUtil getUserServiceUtil(){
               return Mockito.mock(UserServiceUtil.class);
         }
    }
    @Autowired
    private MockMvc mockMvc;
    
    @Autowired
    private WebApplicationContext webApplicationContext ;

    
    
    private String serviceMsg = "serviceMsg";

    @Autowired
    private UserService userService;

    @Autowired
    private UserServiceUtil util;
    
    private User admin;
    private User user;
    
    @Before
    public void setup() {

        mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext ).apply(springSecurity()).build();
        }

    @WithMockUser(username = "test",authorities ="ADMIN")
    @Test
    public void getuserList() throws Exception {
        List<User> list = new ArrayList<User>();
        list.add(new User());
        Page<User> page = new PageImpl<User>(list, null, list.size());
        Mockito.when(userService.getUserSummary(any(Pageable.class))).thenReturn(page);
        this.mockMvc.perform(get("/api/userInfo?page=1&size=10").with(csrf()).contentType(MediaType.APPLICATION_JSON)).
        andExpect(status().isOk()).andDo(MockMvcResultHandlers.print());
      }
    ```

【问题讨论】:

    标签: java spring-boot junit spring-boot-test


    【解决方案1】:

    authoritiesroles 在使用@WithMockUser 时是有区别的:

    /**
     * <p>
     * The roles to use. The default is "USER". A {@link GrantedAuthority} will be created
     * for each value within roles. Each value in roles will automatically be prefixed
     * with "ROLE_". For example, the default will result in "ROLE_USER" being used.
     * </p>
     * <p>
     * If {@link #authorities()} is specified this property cannot be changed from the
     * default.
     * </p>
     * @return
     */
    String[] roles() default { "USER" };
    
    /**
     * <p>
     * The authorities to use. A {@link GrantedAuthority} will be created for each value.
     * </p>
     *
     * <p>
     * If this property is specified then {@link #roles()} is not used. This differs from
     * {@link #roles()} in that it does not prefix the values passed in automatically.
     * </p>
     * @return
     */
    String[] authorities() default {};
    

    无论你用authorities 设置什么都没有任何前缀。

    正如您的控制器所期望的ROLE_ADMIN,请尝试改用roles

    除此之外,我还将尝试使用sliced Spring Context@WebMvcTest 进行此测试。此类测试不需要使用 @SpringBootTest 启动整个 Spring Context。

    【讨论】:

      【解决方案2】:

      删除了@SpringBootTest 并添加了@WebMvcTest 和角色,但得到403。

      
      @RunWith(SpringRunner.class)
      @WebMvcTest(controllers = UserController.class)
      @ActiveProfiles("test")
      @ContextConfiguration
      @AutoConfigureMockMvc(addFilters = false)
      
      public class UserControllerTest {
          
          @Configuration
          
          @EnableGlobalMethodSecurity(prePostEnabled = true)
          protected static class TestConfiguration {
               @Bean
               @Primary
               public UserService getUserService(){
                     return Mockito.mock(UserService.class);
               }
               
               @Bean
               @Primary
               public UserServiceUtil getUserServiceUtil(){
                     return Mockito.mock(UserServiceUtil.class);
               }
          }
          @Autowired
          private MockMvc mockMvc;
          
          @Autowired
          private WebApplicationContext wac;
      
          @Autowired
          private UserService userService;
      
          @Autowired
          private UserServiceUtil util;
      
          
          @Before
          public void setup() {
      
              mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).apply(springSecurity()).build();
                 }
          @WithMockUser(username = "Ram",roles ="ADMIN")
          @Test
          public void getuserList() throws Exception {
              List<User> list = new ArrayList<User>();
              Page<User> page = new PageImpl<User>(list, null, list.size());
              Mockito.when(userService.getUserSummary(any(Pageable.class))).thenReturn(page);
              this.mockMvc.perform(get("/api/userInfo?page=1&size=10").with(csrf()).contentType(MediaType.APPLICATION_JSON)).
              andExpect(status().isOk()).andDo(MockMvcResultHandlers.print());
            }
      }
      
      

      【讨论】:

      • 请不要添加您更新的代码作为您问题的答案。而是用您的更改更新您现有的问题。
      • 您能否添加整个堆栈跟踪并包含MockMvc 打印的错误信息?
      • 此类讨论应视为评论者而非答案。
      猜你喜欢
      • 2019-04-22
      • 2017-07-14
      • 2020-11-20
      • 2010-09-07
      • 1970-01-01
      • 2020-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多