들어가면서
스프링 시큐리티를 적용하면 각 EndPoint를 접근할 때, 권한 인증은 어떻게 고려해서 테스트를 작성해야 하는지 고민이라면 읽어보는 것을 추천한다.
가짜 인증 만들어 인증/인가 단계 처리하기
시큐리티 테스트를 위해서 제공하는 어노테이션을 활용하면 임시로 인증 상태로 만들 수 있다.
1.@WithMockUser
시큐리티의 UsernamePasswordAuthenticationToken
을 만들어서 주입해주는 어노테이션이다.
쉽게 말해서 인증된 유저를 설정하는 기능을 제공한다.
@Test
@WithMockUser
public void getMessageWithMockUser() {
String message = messageService.getMessage();
...
}
아무런 설정없이 사용하면 인증된 유저임을 나타내는 식으로 사용할 수 있고
@Test
@WithMockUser(username="admin",roles={"USER","ADMIN"})
public void getMessageWithMockUserCustomUser() {
String message = messageService.getMessage();
...
}
인증된 유저의 이름과 역할(Role)을 설정할 수도 있다.
@Test
@WithMockUser(username = "admin", authorities = { "ADMIN", "USER" })
public void getMessageWithMockUserCustomAuthorities() {
String message = messageService.getMessage();
...
}
역할이 아니라 권한을 지정하는 방식도 가능하다.
2.@WithAnonymousUser
익명의 유저를 생성하는 어노테이션이다. 특별한 기능적인 차이는 없고 그냥 이름에 익명임을 명시하여 의도를 드러내기 좋은 어노테이션이다.
3.@WithUserDetails
만약에 UserDetailsService
에서 커스텀한 Principal
을 반환하는 식으로 서비스를 개발했다면 @WithMockUser
를 사용하기에는 곤란하다. 그런 경우에 사용하는 것이
이 어노테이션이다. 이 방식은 UserDetailsService
에 의존적인 유저 생성 기능임을 주의해야 한다. 만약 UserDetailsService
에서 오류가 나면 해당 테스트는 작동하지 않을 수 있다!
@Test
@WithUserDetails(value="customUsername", userDetailsServiceBeanName="myUserDetailsService")
public void getMessageWithUserDetailsServiceBeanName() {
String message = messageService.getMessage();
...
}
loadByUsername(String username) 메서드에 쓰이는 username을 value에 입력하는 것이고 userDetailsServiceBeanName은 만약 커스텀한 서비스가 있다면 등록하는 로직이다.
4. @WithSecurityContext
위의 방법은 시큐리티의 매커니즘을 활용한 기능들이기 때문에 유연성은 떨어진다. 그래서 좀 더 유연하게 어떤 인증 로직이더라도 SecurityContext를 사용한다면
테스트를 할 수 있도록 커스텀을 할 수 있다. 이때 사용하는 것이 바로 @WithSecurityContext
이다.
커스텀 절차!
1. 커스텀 모의 인증 객체 선언 어노테이션 만들기
@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
public @interface WithMockCustomUser {
String username() default "rob";
String name() default "Rob Winch";
}
커스텀 어노테이션에 사용할 팩터리 클래스를 매핑한다.
2. 커스텀 Authentication 생성 로직을 구현하는 팩토리 클래스 만들기
public class WithMockCustomUserSecurityContextFactory
implements WithSecurityContextFactory<WithMockCustomUser> {
@Override
public SecurityContext createSecurityContext(WithMockCustomUser customUser) {
SecurityContext context = SecurityContextHolder.createEmptyContext();
CustomUserDetails principal =
new CustomUserDetails(customUser.name(), customUser.username());
Authentication auth =
UsernamePasswordAuthenticationToken.authenticated(principal, "password", principal.getAuthorities());
context.setAuthentication(auth);
return context;
}
}
3. @WithMockCustomUser
를 이용하여 테스트 작성하기
RequestPostProcessor
를 이용한 가짜 유저(인증) 생성
어노테이션 기반으로 가짜 유저(인증)을 만드는 것도 가능하지만 MockMvc에서는 테스트를 하기 위한 기능을 제공한다. 그 역할은 앞에서 배운 것과 동일하다.
1.@WithMockUser
기능과 같은 코드
mvc.perform(get("/admin")
.with(user("admin")
.password("pass")
.roles("USER","ADMIN")))
2.@WithAnonymousUser
기능과 같은 코드
mvc.perform(get("/")
.with(anonymous()))
3. Authentication
주입하여 인증하는 코드
mvc.perform(get("/")
.with(authentication(authentication)))
4. @WithSecurityContext
기능과 같이 컨텍스트 주입하여 인증하는 코드
mvc.perform(get("/")
.with(securityContext(securityContext)))
Reference
'spring > security' 카테고리의 다른 글
[Spring security] SecurityContext, 접근 제한, 권한 제한에 대해서 (0) | 2023.11.07 |
---|---|
[Spring security] PasswordEncoder 살펴보기 (2) | 2023.11.06 |
[Spring security] Redis를 이용한 글로벌 세션 스토리지 (0) | 2023.02.20 |
[Spring] UsernamePasswordAuthenticationFilter 를 통한 폼 로그인 하기 (0) | 2023.02.18 |
Oath2 로그인 구현 - 구글 (0) | 2023.02.13 |