gpt4 book ai didi

java - 如何在 Spring Boot 单元测试中模拟 JWT 身份验证?

转载 作者:行者123 更新时间:2023-12-01 09:39:27 24 4
gpt4 key购买 nike

我已添加 JWT使用 Auth0 进行身份验证到我的 Spring Boot REST API 之后 this example .

现在,正如预期的那样,我以前的工作 Controller单元测试给出的响应代码为 401 Unauthorized而不是 200 OK因为我没有在测试中通过任何 JWT。

我如何模拟 JWT/Authentication我的 REST Controller 测试的一部分?

单元测试类:

    @AutoConfigureMockMvc
public class UserRoundsControllerTest extends AbstractUnitTests {

private static String STUB_USER_ID = "user3";
private static String STUB_ROUND_ID = "7e3b270222252b2dadd547fb";

@Autowired
private MockMvc mockMvc;

private Round round;

private ObjectId objectId;

@BeforeEach
public void setUp() {
initMocks(this);
round = Mocks.roundOne();
objectId = Mocks.objectId();
}

@Test
public void shouldGetAllRoundsByUserId() throws Exception {

// setup
given(userRoundService.getAllRoundsByUserId(STUB_USER_ID)).willReturn(Collections.singletonList(round));

// mock the rounds/userId request
RequestBuilder requestBuilder = Requests.getAllRoundsByUserId(STUB_USER_ID);

// perform the requests
MockHttpServletResponse response = mockMvc.perform(requestBuilder)
.andReturn()
.getResponse();

// asserts
assertNotNull(response);
assertEquals(HttpStatus.OK.value(), response.getStatus());
}

//other tests
}

请求类(上面使用过):
public class Requests {

private Requests() {
}

public static RequestBuilder getAllRoundsByUserId(String userId) {

return MockMvcRequestBuilders
.get("/users/" + userId + "/rounds/")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON);
}

}

Spring 安全配置:
/**
* Configures our application with Spring Security to restrict access to our API endpoints.
*/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Value("${auth0.audience}")
private String audience;

@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuer;

@Override
public void configure(HttpSecurity http) throws Exception {
/*
This is where we configure the security required for our endpoints and setup our app to serve as
an OAuth2 Resource Server, using JWT validation.
*/

http.cors().and().csrf().disable().sessionManagement().
sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
.mvcMatchers(HttpMethod.GET,"/users/**").authenticated()
.mvcMatchers(HttpMethod.POST,"/users/**").authenticated()
.mvcMatchers(HttpMethod.DELETE,"/users/**").authenticated()
.mvcMatchers(HttpMethod.PUT,"/users/**").authenticated()
.and()
.oauth2ResourceServer().jwt();
}

@Bean
JwtDecoder jwtDecoder() {
/*
By default, Spring Security does not validate the "aud" claim of the token, to ensure that this token is
indeed intended for our app. Adding our own validator is easy to do:
*/

NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
JwtDecoders.fromOidcIssuerLocation(issuer);

OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience);
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);
OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);

jwtDecoder.setJwtValidator(withAudience);

return jwtDecoder;
}


@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}

抽象单元测试类:
@ExtendWith(SpringExtension.class)
@SpringBootTest(
classes = PokerStatApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
public abstract class AbstractUnitTests {

// mock objects etc


}

最佳答案

如果我正确理解您的情况,则有一种解决方案。

在大多数情况下,如果 token 存在于请求头中,JwtDecoder bean 会执行 token 解析和验证。

来自您的配置示例:

    @Bean
JwtDecoder jwtDecoder() {
/*
By default, Spring Security does not validate the "aud" claim of the token, to ensure that this token is
indeed intended for our app. Adding our own validator is easy to do:
*/

NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
JwtDecoders.fromOidcIssuerLocation(issuer);

OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience);
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);
OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);

jwtDecoder.setJwtValidator(withAudience);

return jwtDecoder;
}

所以对于测试,你需要添加这个 bean 的 stub ,并且为了在 spring 上下文中替换这个 bean,你需要使用它的测试配置。

它可能是这样的:
@TestConfiguration
public class TestSecurityConfig {

static final String AUTH0_TOKEN = "token";
static final String SUB = "sub";
static final String AUTH0ID = "sms|12345678";

public JwtDecoder jwtDecoder() {
// This anonymous class needs for the possibility of using SpyBean in test methods
// Lambda cannot be a spy with spring @SpyBean annotation
return new JwtDecoder() {
@Override
public Jwt decode(String token) {
return jwt();
}
};
}

public Jwt jwt() {

// This is a place to add general and maybe custom claims which should be available after parsing token in the live system
Map<String, Object> claims = Map.of(
SUB, USER_AUTH0ID
);

//This is an object that represents contents of jwt token after parsing
return new Jwt(
AUTH0_TOKEN,
Instant.now(),
Instant.now().plusSeconds(30),
Map.of("alg", "none"),
claims
);
}

}

要在测试中使用此配置,只需选择此测试安全配置:
@SpringBootTest(classes = TestSecurityConfig.class)
同样在测试请求中应该是带有像 Bearer .. something 这样的 token 的授权 header 。

以下是有关您的配置的示例:
    public static RequestBuilder getAllRoundsByUserId(String userId) {

return MockMvcRequestBuilders
.get("/users/" + userId + "/rounds/")
.accept(MediaType.APPLICATION_JSON)
.header(HttpHeaders.AUTHORIZATION, "Bearer token"))
.contentType(MediaType.APPLICATION_JSON);
}

关于java - 如何在 Spring Boot 单元测试中模拟 JWT 身份验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61500578/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com