본 프로젝트는 “스프링부트 3 백엔드 개발자 되기” 서적을 참고하여 진행하였음
OAuth 인증 적용 위한 테스트 코드 작성
•
테스트코드 수정 - 굵은 글씨로 표시한 부분 참고
package com.example.msblog.controller;
import com.example.msblog.domain.Article;
import com.example.msblog.domain.User;
import com.example.msblog.dto.AddArticleRequest;
import com.example.msblog.dto.UpdateArticleRequest;
import com.example.msblog.repository.BlogRepository;
import com.example.msblog.repository.UserRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.security.Principal;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest // 테스트용 애플리케이션 컨택스트
@AutoConfigureMockMvc // MockMvc 생성 및 자동 구성
class BlogApiControllerTest {
@Autowired
protected MockMvc mockMvc;
@Autowired
protected ObjectMapper objectMapper; // 직렬화, 역직렬화를 위한 클래스
@Autowired
private WebApplicationContext context;
@Autowired
BlogRepository blogRepository;
// 추가
@Autowired
UserRepository userRepository;
// 추가
User user;
// 추가
@BeforeEach
@Test
void setSecurityContext() {
userRepository.deleteAll();
user = userRepository.save(User.builder()
.email("user@gmail.com")
.password("test")
.build());
// 인증 객체를 저장하는 시큐리티 콘텍스트에 setAuthentication() 메서드를 사용해 테스트 유저를 지정한다.
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(new UsernamePasswordAuthenticationToken(user,
user.getPassword(), user.getAuthorities()));
}
@BeforeEach // 테스트 실행 전 실행하는 메서드
public void mockMvcSetUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
blogRepository.deleteAll();
}
@DisplayName("addArticle: 블로그 글 추가에 성공한다.")
@Test
public void addArticle() throws Exception {
// given
final String url = "/api/articles";
final String title = "title";
final String content = "content";
final AddArticleRequest userRequest = new AddArticleRequest(title, content);
// 객체 JSON으로 직렬화하기
final String requestBody = objectMapper.writeValueAsString(userRequest);
// 추가 - 글을 생성하는 API에서는 파라미터로 Principal 객체를 받고 있는데 이 객체에 테스트 유저가 들어가도록 모킹한다.
// 해당 테스트 코드에서는 Principal 객체를 모킹해서 스프링 부트 애플리케이션에서 getName() 메서드를 호출하면 "userName" 이라는 값을 반환한다.
Principal principal = Mockito.mock(Principal.class);
Mockito.when(principal.getName()).thenReturn("username");
// when
// mockMvc 활용하여 HTTP 메서드, URL, 요청 본문, 요청 타입 등을 설정한 뒤 설정한 내용을 바탕으로 테스트 요청을 보냄
// 설정한 내용 바탕으로 요청 전송
ResultActions result = mockMvc.perform(post(url)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.principal(principal) // 추가
.content(requestBody));
// then
result.andExpect(status().isCreated());
List<Article> articles = blogRepository.findAll();
assertThat(articles.size()).isEqualTo(1); // 크기가 1인지 검증
assertThat(articles.get(0).getTitle()).isEqualTo(title);
assertThat(articles.get(0).getContent()).isEqualTo(content);
}
@DisplayName("findAllAritcles: 블로그 글 목록 조회에 성공한다.")
@Test
public void findAllArticles() throws Exception {
// given
final String url = "/api/articles";
Article savedArticle = createDefaultArticle(); // 추가
// when
final ResultActions resultActions = mockMvc.perform(get(url)
.accept(MediaType.APPLICATION_JSON));
// then
resultActions
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].content").value(savedArticle.getContent())) // 수정
.andExpect(jsonPath("$[0].title").value(savedArticle.getTitle())); // 수정
}
@DisplayName("findArticle: 블로그 글 조회에 성공한다.")
@Test
public void findArticle() throws Exception {
// given
final String url = "/api/articles/{id}";
Article savedArticle = createDefaultArticle(); // 추가
// when
final ResultActions resultActions = mockMvc.perform(get(url, savedArticle.getId()));
// then
resultActions
.andExpect(status().isOk())
.andExpect(jsonPath("$.content").value(savedArticle.getContent())) // 수정
.andExpect(jsonPath("$.title").value(savedArticle.getTitle())); // 수정
}
@DisplayName("deleteArticle: 블로그 글 삭제에 성공한다.")
@Test
public void deleteArticle() throws Exception {
// given
final String url = "/api/articles/{id}";
Article savedArticle = createDefaultArticle(); // 추가
// when
mockMvc.perform(delete(url, savedArticle.getId()))
.andExpect(status().isOk());
// then
List<Article> articles = blogRepository.findAll();
assertThat(articles).isEmpty();
}
@DisplayName("updateArticle: 블로그 글 수정에 성공한다.")
@Test
public void updateArticle() throws Exception {
// given
final String url = "/api/articles/{id}";
Article savedArticle = createDefaultArticle(); // 추가
final String newTitle = "new title";
final String newContent = "new content";
UpdateArticleRequest request = new UpdateArticleRequest(newTitle, newContent);
// when
ResultActions result = mockMvc.perform(put(url, savedArticle.getId())
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(objectMapper.writeValueAsString(request)));
// then
result.andExpect(status().isOk());
Article article = blogRepository.findById(savedArticle.getId()).get();
assertThat(article.getTitle()).isEqualTo(newTitle);
assertThat(article.getContent()).isEqualTo(newContent);
}
// 중복 코드 제거하기 위해 글을 만드는 로직을 해당 메서드로 추출한다.
private Article createDefaultArticle() {
return blogRepository.save(Article.builder()
.title("title")
.author(user.getUsername())
.content("content")
.build());
}
}
Java
복사
핵심 요약
1.
쿠키란 사용자가 어떠한 웹사이트를 방문했을 때, 그 웹사이트가 사용하는 서버를 통해 로컬에 저장되는 작은 데이터이다. 쿠키는 키와 값으로 이루어져 있으며 만료 기간, 도메인 등의 정보를 가지고 있다.
2.
OAuth는 제3의 서비스에게 계정을 맡기는 방식이다. OAuth 에서 정보를 취득하는 방법은 권한 부여 코드 승인 타입, 암시적 승인 타입, 리소스 소유자 암호 자격증명 승인 타입, 클라이언트 자격증명 승인 타입으로 나뉜다.
3.
OAuth 방식 중 권한 부여 코드 승인 타입은 클라이언트가 리소스에 접근하는 데 사용되며, 권한에 접근할 수 있는 코드를 제공받으면 리소스 오너에 대한 액세스 토큰을 제공받게 된다.