您只能在集成测试中测试执行器端点访问控制 (@SpringBootTest)。对于您自己的安全 @Components,您也可以在单元测试中进行(this repo 中的许多示例):
-
@Controller 和 @WebMvcTest(@WebfluxTest 如果您使用的是响应式应用程序)
- 普通 JUnit,带有测试组件的
@ExtendWith(SpringExtension.class)、@EnableMethodSecurity 和 @Import(@Service 或 @Repository,方法安全性类似于 @PreAuthorize 表达式),以获取具有安全性的自动装配实例
spring-security-test 带有一些 MockMvc 请求后处理器(在你的情况下请参阅org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt)以及 WebTestClient 突变器(请参阅org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockJwt)以配置正确类型的身份验证(在你的情况下为JwtAuthenticationToken)并将其设置为测试安全上下文,但这仅限于 MockMvc 和 WebTestClient 以及 @Controller 测试。
执行器启动的集成测试 (@SpringBootTest) 中的示例用法(但您了解单元测试的想法):
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt;
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
class ApplicationIntegrationTest {
@Autowired
MockMvc api;
@Test
void givenUserIsAnonymous_whenGetLiveness_thenOk() throws Exception {
api.perform(get("/data/actuator/liveness"))
.andExpect(status().isOk());
}
@Test
void givenUserIsAnonymous_whenGetMachin_thenUnauthorized() throws Exception {
api.perform(get("/data/machin"))
.andExpect(status().isUnauthorized());
}
@Test
void givenUserIsGrantedWithDataWrite_whenGetMachin_thenOk() throws Exception {
api.perform(get("/data/machin")
.with(jwt().jwt(jwt -> jwt.authorities(List.of(new SimpleGrantedAuthority("SCOPE_data:write"))))))
.andExpect(status().isOk());
}
@Test
void givenUserIsAuthenticatedButNotGrantedWithDataWrite_whenGetMachin_thenForbidden() throws Exception {
api.perform(get("/data/machin")
.with(jwt().jwt(jwt -> jwt.authorities(List.of(new SimpleGrantedAuthority("SCOPE_openid"))))))
.andExpect(status().isForbidden());
}
}
您也可以使用 this libs I maintain 中的 @WithMockJwtAuth。这个 repo 包含相当多的单元和集成测试示例,用于任何类型的@Component(当然是@Controllers,还有@Services 或@Repositories 用方法安全性装饰)。
以上示例变为:
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-oauth2-test</artifactId>
<version>6.0.12</version>
<scope>test</scope>
</dependency>
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
class ApplicationIntegrationTest {
@Autowired
MockMvc api;
@Test
void givenUserIsAnonymous_whenGetLiveness_thenOk() throws Exception {
api.perform(get("/data/actuator/liveness"))
.andExpect(status().isOk());
}
@Test
void givenUserIsAnonymous_whenGetMachin_thenUnauthorized() throws Exception {
api.perform(get("/data/machin"))
.andExpect(status().isUnauthorized());
}
@Test
@WithMockJwtAuth("SCOPE_data:write")
void givenUserIsGrantedWithApiRead_whenGetMachin_thenOk() throws Exception {
api.perform(get("/data/machin"))
.andExpect(status().isOk());
}
@Test
@WithMockJwtAuth("SCOPE_openid")
void givenUserIsAuthenticatedButNotGrantedWithApiRead_whenGetMachin_thenForbidden() throws Exception {
api.perform(get("/data/machin"))
.andExpect(status().isForbidden());
}
}
Spring-addons 启动器
在与测试注释相同的 repo 中,您会发现简化您的资源服务器安全配置的启动器(并且还可以改进您的 CORS 配置并同步会话和 CSRF 保护禁用第二个不应在活动会话中被禁用...)。
使用超级简单要切换到另一个 OIDC 授权服务器,您需要更改的只是属性.例如,这可能是因为您被忙碌所迫(如果他们认为 Auth0 太贵或不再受信任)或者可能是因为您发现在您的开发机器上使用独立的 Keycloak 更方便(它是离线可用,我经常这样做)。
不要直接导入 spring-boot-starter-oauth2-resource-server,而是在它周围导入一个薄包装(仅限 composed of 3 files):
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<artifactId>spring-addons-webmvc-jwt-resource-server</artifactId>
<version>6.0.12</version>
</dependency>
默认情况下,用户必须经过身份验证才能访问除com.c4-soft.springaddons.security.permit-all 属性中列出的任何路由(见下文)。将所有 Java conf 替换为:
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
}
将 spring.security.oauth2.resourceserver 属性替换为:
# Single OIDC JWT issuer but you can add as many as you like
com.c4-soft.springaddons.security.issuers[0].location=https://dev-ch4mpy.eu.auth0.com/
# Mimic spring-security default converter: map authorities with "SCOPE_" prefix
# Difference with your current conf is authorities source is not only "scope" claim but also "roles" and "permissions" ones
# I would consider map authorities without "SCOPE_" prefix (the default behaviour of my starters) and update access control expressions accordingly
com.c4-soft.springaddons.security.issuers[0].authorities.claims=scope,roles,permissions
com.c4-soft.springaddons.security.issuers[0].authorities.prefix=SCOPE_
# Fine-grained CORS configuration can be set per path as follow:
com.c4-soft.springaddons.security.cors[0].path=/data/api/**
com.c4-soft.springaddons.security.cors[0].allowed-origins=https://localhost,https://localhost:8100,https://localhost:4200
com.c4-soft.springaddons.security.cors[0].allowedOrigins=*
com.c4-soft.springaddons.security.cors[0].allowedMethods=*
com.c4-soft.springaddons.security.cors[0].allowedHeaders=*
com.c4-soft.springaddons.security.cors[0].exposedHeaders=*
# Comma separated list of ant path matchers for resources accessible to anonymous
com.c4-soft.springaddons.security.permit-all=/data/actuator/**
骗子,不是吗?