SpringSecurity

SpringSecurity [HttpSecurity] 접근 권한 [TestCode]

성찬우 2022. 6. 24. 00:04

의존성

security-test 

security

 

관련 어노테이션 

import org.junit.Test;

//1
@Test
@WithMockUser(username = "userforTest", roles = "USER")

//2
@Test
@WithMockUser(username = "adminforTest", roles = "ADMIN")

//3
@Test
@WithAnonymousUser

 

우리는 SpringSecurity 를 사용 할 때. 유저의 로그인이 필요한 페이지 인지 아닌지 구분하여 

유저 인증에 따른 페이지 인가를 내어 줄수 있다. 

 

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .mvcMatchers("/", "/info", "/account/**").permitAll()
            .mvcMatchers("/admin").hasRole("ADMIN")
            .anyRequest().authenticated();
    http.formLogin();
    http.httpBasic();

    return http.build();
}

예를 들어 위에 코드는

"/", "/info",  "/account/** " 의 경우 인증을 했는지 아닌지를 떠나서 모두 접근이 가능하고 

/admin 페이지는 해당 유저의 권한이 "ADMIN" 이여야 접근이 가능하다. 

다른 요청을 모두 인증을 받아야 한다. 

 

우리가 이 코드가 제대로 작동을 하는지 확인을 하기 위해서는 

localhost:8080으로 확인을 할 수도 있지만 매번 확인하는데에는 무리가 있으므로 

테스트 코드로 확인을 할 수 있도록 해야한다. 

 

 

1. permitAll() 페이지

@Test
@WithAnonymousUser
public void index_user() throws Exception {
    mockMvc.perform(get("/"))
            .andDo(print())
            .andExpect(status().isOk());
}

"/" 로 들어오는 인증이 안된 유저로 테스트를 할 것이다. 

@WithAnonymousUser 어노테이션은 인증이 안된 유저를 뜻한다. 

(만약 permitAll()이 아닌 anonymous() 로 되어있는 페이지가 있다면 유저는 접근 할 수 없다. )

 

mockMvc를 통해 getMapping ("/")에 요청을 보내고 아무런 오류가 없어야 한다. 

 

2. mvcMatchers("/admin").hasRole("ADMIN")  관련 페이지 

해당 유저의 role이 ADMIN이여야 접근이 가능하다. 유저를 하나 생성해줄 수 있는데 

@Test
@WithMockUser(username = "adminforTest", roles = "ADMIN")

WithMockUser에는 다양한 설정을 할 수 있는데 

[ value, nsername, roles, authorities, password ]가 존재한다. 

 

해당 코드로 유저를 간단하게 만들어 줄수 있다. 

@Test
@WithMockUser(username = "adminforTest", roles = "ADMIN") //adminforTest 아이디를 가진 ADMIN 유저 
public void admin_page_ADMIN() throws Exception {
    mockMvc.perform(get("/admin"))
            .andDo(print())
            .andExpect(status().isOk());
}

당연히 admin 페이지는 ADMIN만 접근할 수 있으므로 오류가 없어야 한다. 

 

 

 

 

이 외에도 ADMIN이 아닌데 /admin 페이지에 접근하려고 할 시에 

.andExpect(status().isOk());// 대신에
.andExpect(status().isForbidden()); //이걸 사용해서

 

테스트를 완성 시킬수 있다. 

 

하지만 여기서 또하나의 반복 수행이 나온다. 

각 테스트 마다 유저를 계속해서 만들어 내야한다는 것.

유저를 어노테이션화 시켜보자. 

 

3. @WithMockUser(username = "adminforTest", roles = "ADMIN") 어노테이션화 하기 

 

 

 

우선 WithAdmin이라는 Anotation 클래스를 생성한다. 

 

public @interface WithAdmin {
}

이러한 클래스가 생성이 되는데 

@WithMockUser(username = "adminforTest", roles = "ADMIN")
public @interface WithAdmin {
}

이렇게 우리가 사용할 유저를 가져와서 그대로 적어주면 된다. 또한

@WithMockUser(username = "adminforTest", roles = "ADMIN")
@Retention(RetentionPolicy.RUNTIME)
public @interface WithAdmin {
}

@Retention 

애노테이션의 [라이프 사이클] ->  애노테이션이 언제까지 살아 남아 있을지를 정하는 것이다. 

우리는 런타임 까지 정해주었다. 

 

이후

@Test
@WithAdmin
public void admin_page_ADMIN() throws Exception {
    mockMvc.perform(get("/admin"))
            .andDo(print())
            .andExpect(status().isOk());
}

간단하게 해당 어노테이션을 가져다가 사용하면 된다. 

 

매우 간단하다.