JWT 토큰보안에 의한 스프링부트 유닛 테스트
Spring Boot을 사용하여 백엔드를 만들고 있으며 JWT 보안을 추가한 지 얼마 되지 않았습니다.
REST 클라이언트를 사용하여 몇 가지 테스트를 수행했으며 JWT 보안은 정상적으로 작동하지만 모든 장치 테스트에서 403 오류 코드가 반환되었습니다.
를 추가했습니다.@WithMockUser
주석을 달았지만 여전히 작동하지 않습니다.
@Test
@WithMockUser
public void shouldRedirectToInstaAuthPage() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/instaAuth")).andExpect(status().is3xxRedirection());
}
여기에 없는 다른 설정이 있나요?
보안 설정은 다음과 같습니다.
@Configuration
@EnableWebSecurity
public class ServerSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new JWTLoginFilter("/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
// And filter other requests to check the presence of JWT in header
.addFilterBefore(new JWTAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Create a default account
auth.inMemoryAuthentication()
.withUser("john")
.password("123")
.roles("ADMIN");
}
}
방법 보안:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
문제를 해결했다고 생각합니다(또한 백엔드에 보안 취약점을 만들거나 나쁜 방법을 사용하지 않았으면 합니다).
저는 @punkrocker27ka의 조언에 따라 이 답변을 보았습니다.테스트용으로 Oauth 토큰을 수동으로 생성한다고 되어 있기 때문에 JWT 토큰에도 같은 처리를 하기로 했습니다.
그래서 JWT 토큰을 생성하는 클래스를 업데이트하고 다음과 같이 검증했습니다.
public class TokenAuthenticationService {
static final long EXPIRATIONTIME = 864_000_000; // 10 days
static final String SECRET = "ThisIsASecret";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";
public static void addAuthentication(HttpServletResponse res, String username) {
String jwt = createToken(username);
res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + jwt);
}
public static Authentication getAuthentication(HttpServletRequest request) {
String token = request.getHeader(HEADER_STRING);
if (token != null) {
// parse the token.
String user = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
.getBody()
.getSubject();
return user != null ?
new UsernamePasswordAuthenticationToken(user, null, Collections.emptyList()) :
null;
}
return null;
}
public static String createToken(String username) {
String jwt = Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
return jwt;
}
}
그리고 나서 새로운 테스트를 만들었습니다.
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class TokenAuthenticationServiceTest {
@Autowired
private MockMvc mvc;
@Test
public void shouldNotAllowAccessToUnauthenticatedUsers() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/test")).andExpect(status().isForbidden());
}
@Test
public void shouldGenerateAuthToken() throws Exception {
String token = TokenAuthenticationService.createToken("john");
assertNotNull(token);
mvc.perform(MockMvcRequestBuilders.get("/test").header("Authorization", token)).andExpect(status().isOk());
}
}
그 후 테스트를 실행했는데 통과했으므로 토큰이 승인되었습니다.@WithMockUser
주석입니다.나는 이것을 나의 다른 시험 수업에 추가할 것이다.
PS: 테스트 엔드 포인트는 다음과 같습니다.
/**
* This controller is used only for testing purposes.
* Especially to check if the JWT authentication is ok.
*/
@RestController
public class TestController {
@RequestMapping(path = "/test", method = RequestMethod.GET)
public String testEndpoint() {
return "Hello World!";
}
}
이 Create를 사용하여 테스트하는 경우 주의해야 할 것은Token() 메서드는 존재하지 않는 사용자를 테스트할 수 없습니다.
이는 create가Token()은 입력한 문자열을 기반으로 JWT 토큰만 만듭니다.
존재하지 않는 사용자가 액세스 할 수 없도록 하려면 다음 명령을 생성할 것을 권장합니다.Token() 메서드 private는 다음과 같이 요구를 사용하여 토큰을 가져옵니다.
@Test
public void existentUserCanGetTokenAndAuthentication() throws Exception {
String username = "existentuser";
String password = "password";
String body = "{\"username\":\"" + username + "\", \"password\":\"
+ password + "\"}";
MvcResult result = mvc.perform(MockMvcRequestBuilders.post("/v2/token")
.content(body))
.andExpect(status().isOk()).andReturn();
String response = result.getResponse().getContentAsString();
response = response.replace("{\"access_token\": \"", "");
String token = response.replace("\"}", "");
mvc.perform(MockMvcRequestBuilders.get("/test")
.header("Authorization", "Bearer " + token))
.andExpect(status().isOk());
}
마찬가지로 존재하지 않는 사용자가 다음 결과를 얻을 수 없음을 나타낼 수 있습니다.
@Test
public void nonexistentUserCannotGetToken() throws Exception {
String username = "nonexistentuser";
String password = "password";
String body = "{\"username\":\"" + username + "\", \"password\":\"
+ password + "\"}";
mvc.perform(MockMvcRequestBuilders.post("/v2/token")
.content(body))
.andExpect(status().isForbidden()).andReturn();
}
언급URL : https://stackoverflow.com/questions/45241566/spring-boot-unit-tests-with-jwt-token-security
'source' 카테고리의 다른 글
Angular에서 "취소"를 처리하는 패턴이 있습니까?JS 모달 대화 상자? (0) | 2023.03.08 |
---|---|
WordPress: 작성자 상자에 표시되지 않는 사용자 지정 사용자 (0) | 2023.03.08 |
react에 노드가 정말로 필요한가?프런트 엔드 ENV의 JS? (0) | 2023.03.08 |
jQuery를 사용하여 JSON 어레이의 키/값 쌍 루프 및 가져오기 (0) | 2023.03.08 |
AngularJS 및 그 달러 변수 사용 (0) | 2023.03.08 |