我有以下 Spring Security 6 配置:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeHttpRequests(registry -> registry
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2Configurer -> oauth2Configurer.jwt(jwtConfigurer -> jwtConfigurer.jwtAuthenticationConverter(jwt -> {
Map<String, Collection<String>> realmAccess = jwt.getClaim("realm_access");
Collection<String> roles = realmAccess.get("roles");
var grantedAuthorities = roles.stream()
.map(role -> new SimpleGrantedAuthority(role))
.collect(Collectors.toList());
return new JwtAuthenticationToken(jwt, grantedAuthorities);
})));
httpSecurity.sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
httpSecurity.csrf(CsrfConfigurer::disable);
// Disable anonymous
httpSecurity.anonymous(AnonymousConfigurer::disable);
return httpSecurity.build();
}
无需授权即可使用的公共端点:
@RestController
@RequestMapping(value = "/uaa/")
public class ApikeyAuthController {
......
@PostMapping(value = "/public", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> apiKey(@RequestBody MultiValueMap<String, String> requestBody)
{
.......
return new ResponseEntity<>(HttpStatus.OK);
}
}
JUnit 测试:
@AutoConfigureMockMvc
@ContextConfiguration(classes = {ApikeyAuthController.class})
@WebMvcTest
public class ApikeyAuthControllerTest {
@MockBean
private ApiKeyService service;
@MockBean
private TokenService tokenService;
@MockBean
private ApiKeyAuthValidator apiKeyAuthValidator;
@Autowired
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@BeforeEach
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void apiKeyTest() throws Exception
{
when(service.getSummary(any(), any())).thenReturn(Optional.of(List.of(SummaryDTO.builder()
.date(LocalDateTime.of(2021, Month.MAY, 1, 12, 13))
.enabled(12)
.disabled(5)
.build())));
MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
requestBody.add("key", "password");
this.mockMvc.perform(MockMvcRequestBuilders
.post("/public")
.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.content(requestBody.toString()))
.andExpect(MockMvcResultMatchers.status().isOk());
}
}
我总是收到 http 代码 401(未经授权)。 您知道如何配置 /public 端点以在未经授权的情况下接受上述端点的请求吗?
有多种方法可以选择模拟安全功能,例如使用
SecurityMockMvcRequestPostProcessors
中的 spring-security-test
,或如所描述的 @WithMockUser
,例如在文档中这里。
我个人更喜欢嘲笑
SecurityFilterChain
bean:
@WebMvcTest(ApikeyAuthController.class)
@MockBean(SecurityFilterChain.class)
class ApikeyAuthControllerTest {
@Autowired
private MockMvc mockMvc;
}
顺便说一下:
@ContextConfiguration
来指定被测试的控制器,在@WebMvcTest注释中设置它。mockMvc
注释之外,您不需要初始化 @Autowired
,因此您可以删除 @BeforeEach
方法。