Spring Boot - 使用自定义 PreAuthorize 表达式和身份验证测试 Rest Api
Posted
技术标签:
【中文标题】Spring Boot - 使用自定义 PreAuthorize 表达式和身份验证测试 Rest Api【英文标题】:Spring Boot - Test Rest Api With Custom PreAuthorize Expression and Authentication 【发布时间】:2018-10-07 10:53:00 【问题描述】:我正在寻找一种如何使用以下设置测试 Spring Boot REST API 的方法:
@RestController
class SomeRestController
@Autowired
private SomeService someService;
@GetMapping("/getSome")
@PreAuthorize("@canGetSome.isValid()")
public SomeObject getSomeObject()
return someService.getSomeObject();
_
@Component
public class CanGetSome
@Autowired
private final LoggedUser loggedUser;
public boolean isValid()
return loggedUser.getPermissions().isCanGetSome();
_
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
...
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
http
.sessionManagement()
.sessionFixation().newSession()
.and()
.authorizeRequests())
.anyRequest().authenticated();
//custom LoggedUser object which is initzialized on authentication sucessfull
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public LoggedUser loggedUser()
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return (LoggedUser) authentication.getPrincipal();
...
我的测试用例:
@SpringBootTest(
classes = SpringBootApplication,
webEnvironment = RANDOM_PORT)
@ContextConfiguration
class RestSecurityTest extends Specification
@Autowired
private TestRestTemplate testRestTemplate
@LocalServerPort
private int port
@WithCustomMockUser
def "test testRestTemplare"()
expect:
def respone = testRestTemplate.getForObject('http://localhost:'+ port+'/getSome', String)
_
public class WithCustomMockUserSecurityContextFactory implements WithSecurityContextFactory<WithCustomMockUser>
@Override
public SecurityContext createSecurityContext(WithCustomMockUser annotation)
//init securityContext like @WithMockUser but with LoggedUser as principal which return true on loggedUser.getPermissions().isCanGetSome();
不幸的是,我在测试中得到以下响应:
"timestamp": 1524759173851,
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/getSome"
我还在请求后调试不同的spring过滤器,SecurityContext身份验证为null,后来切换到AnonymousAuthenticationToken
我不知道为什么 SecurityContext 在请求后为空,而不是使用 @WithCustomMockUser 注释初始化的 SecurityContext。任何想法如何解决它?
【问题讨论】:
它在您的测试之外工作吗? 你试过this吗?我通过了一个类似的问题,这个解决方案(有一些变化)对我有用。试试看,在这里告诉我们结果。 PS.:尝试使用 MockMvc,我无法使用 TestRestTemplate。 【参考方案1】:Spring MVC 应该是要走的路。
测试类:-
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
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;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestContext.class, TestWebMvcConfigurerAdapter.class, SecurityConfiguration .class )
@WebAppConfiguration
public class SomeControllerTest
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@Autowired
private FilterChainProxy springSecurityFilterChain;
@Before
public void setUp()
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext)
.addFilters(this.springSecurityFilterChain)
.build();
@Test
public void shouldPreAuthorise() throws Exception
this.mockMvc.perform(get("/getSome")
.with(user("user.name"))
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
测试网页配置器:-
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages =
"your.package.here"
)
public class TestWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter
一些模拟对象:-
@Configuration
public class TestContext
@Bean
public SomeService someService()
return mock(SomeService.class);
【讨论】:
是否可以使用 spock 进行此设置?以上是关于Spring Boot - 使用自定义 PreAuthorize 表达式和身份验证测试 Rest Api的主要内容,如果未能解决你的问题,请参考以下文章
spring boot spring security 基于自定义令牌的身份验证和自定义授权
使用自定义 ErrorAttributes 测试 Spring Boot 应用程序?
使用自定义 ErrorAttributes 测试 Spring Boot 应用程序?
企业级spring-boot案例-自定义Spring Boot Starter