Java 简单地测试 Spring Boot 安全性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31812054/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:37:49  来源:igfitidea点击:

Testing Spring Boot Security simply

javaspringsecuritytestingspring-boot

提问by Jakub Koz?owski

I'm struggling with testing access control on URLs protected by Spring Security.

我正在努力测试受 Spring Security 保护的 URL 的访问控制。

The configuration looks like this:

配置如下所示:

    http
            .authorizeRequests()
            .antMatchers("/api/user/**", "/user").authenticated()
            .antMatchers("/api/admin/**", "/templates/admin/**", "/admin/**").hasAuthority("ADMIN")
            .anyRequest().permitAll();

And the test class looks like this:

测试类如下所示:

package com.kubukoz.myapp;

import com.kubukoz.myapp.config.WebSecurityConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import javax.transaction.Transactional;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {MyApplication.class, WebSecurityConfig.class})
@WebAppConfiguration
@TransactionConfiguration(defaultRollback = true)
@Transactional(rollbackOn = Exception.class)
public class MyApplicationTests {

    @Autowired
    private WebApplicationContext context;
    private MockMvc mockMvc;
    @Autowired
    private FilterChainProxy filterChainProxy;

    @Before
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(context)
                .dispatchOptions(true)
                .addFilters(filterChainProxy)
                .build();
    }

    @Test
    public void testAnonymous() throws Exception {
        mockMvc.perform(get("/api/user/account")).andExpect(status().is3xxRedirection());
    }

    @Test
    public void testUserAccessForAccount() throws Exception{
        mockMvc.perform(get("/api/user/account")).andExpect(status().isOk());
    }
}

What's the easiest way to make the last two tests pass? @WithMockUser didn't work.

使最后两个测试通过的最简单方法是什么?@WithMockUser 没有用。

采纳答案by Rob Winch

You should not add the FilterChainProxy directly. Instead, you should apply SecurityMockMvcConfigurers.springSecurity()as indicated by the reference. An example is included below:

您不应直接添加 FilterChainProxy。相反,您应该SecurityMockMvcConfigurers.springSecurity()按照参考中的指示进行申请。下面包含一个示例:

mockMvc = MockMvcBuilders
            .webAppContextSetup(context)
            .apply(springSecurity())
            .build();

The result of this is:

这样做的结果是:

  • the FilterChainProxyis added as a Filterto MockMvc(as you did)
  • the TestSecurityContextHolderPostProcessoris added
  • FilterChainProxy被添加为FilterMockMvc(像你一样)
  • TestSecurityContextHolderPostProcessor加入

Why is TestSecurityContextHolderPostProcessornecessary? The reason is that we need to communicate the current user from the test method to the MockHttpServletRequestthat is created. This is necessary because Spring Security's SecurityContextRepositoryFilterwill override any value on SecurityContextHolderto be the value found by the current SecurityContextRepository(i.e. the SecurityContextin HttpSession).

为什么是TestSecurityContextHolderPostProcessor必要的?原因是我们需要将当前用户从测试方法传递到MockHttpServletRequest创建的方法。这是必要的,因为 Spring SecuritySecurityContextRepositoryFilter将覆盖任何值 onSecurityContextHolder为当前找到的值SecurityContextRepository(即SecurityContextin HttpSession)。

Update

更新

Remember anything that contains role in the method name automatically prefixes "ROLE_" to the string that was passed in.

请记住,方法名称中包含角色的任何内容都会自动将“ROLE_”作为传入字符串的前缀。

Based on your comment, the problem is you need to either update your configuration to use hasRole instead of hasAuthority (since your annotation is using roles):

根据您的评论,问题是您需要更新配置以使用 hasRole 而不是 hasAuthority (因为您的注释使用角色):

.authorizeRequests()
            .antMatchers("/api/user/**", "/user").authenticated()
            .antMatchers("/api/admin/**", "/templates/admin/**", "/admin/**").hasRole("ADMIN")
            .anyRequest().permitAll();

Alternatively

或者

You in Spring Security 4.0.2+ you can use:

您在 Spring Security 4.0.2+ 中可以使用:

@WithMockUser(authorities="ADMIN")

回答by Jakub Koz?owski

Okay, figured it out.

好的,想通了。

mockMvc.perform(get("/api/user/account")
      .with(user("user")))
      .andExpect(status().isOk());

It works now.

它现在有效。