OAuth2.0 의 흐름
OAuth2.0의 로그인 과정에 대해 너무나 자세히 잘 알려주고 있기때문에 참고하면 좋을거 같습니다!!
나도 OAuth를 사용하던 중에 어떻게 yml에 설정한 정보를 갖고와서 인가 코드를 받고 인가코드로 토큰을 받고 그 토큰으로 사용자 정보를 요청할 수 있는것인지 궁금했는데 이 글을 보고 해결되었다.
자료 추천
먼저 OAuth로그인을 통해서 사용자를 저장해야하기때문에
Member 라는 Entity 설정
package com.qkrtprjs.happyexercise.member;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter
@Entity
@NoArgsConstructor
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String email;
private String picture;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role;
@Builder
public Member(String name, String email, String picture, Role role) {
this.name = name;
this.email = email;
this.picture = picture;
this.role = role;
}
}
먼저 회원가입 API를 만들어준뒤 이상이 없는지 테스트해보고 OAuth 로그인을 진행하자
먼저 RestController를 만들어줍니다.
이전 프로젝트를 진행할때에는 MVC패턴을 사용해서 컨트롤러에서 model에 값을 넣어서 뷰로 전달하는 방식으로 사용했다면 이번 프로젝트에서 API를 만들어줄때에는 REST-API 방식으로 진행하려고한다. 짧게나마 REST-API방식에 대해 설명하자면 자원과 HTTP메서드 방식을 통해서 API 설계하는 것이다 즉, url과 http메서드로 무슨 동작을 수행할 것인지 짐작할 수 있는 형태의 API를 뜻하고 JOSN을 리턴합니다.
package com.qkrtprjs.happyexercise.controller;
import com.qkrtprjs.happyexercise.dto.MemberSaveRequestDto;
import com.qkrtprjs.happyexercise.member.Member;
import com.qkrtprjs.happyexercise.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class MemberApiController {
private final MemberService memberService;
@PostMapping("/api/member")
private Long save(@RequestBody MemberSaveRequestDto memberSaveRequestDto) {
return memberService.save(memberSaveRequestDto);
}
}
해당 서비스 부분
package com.qkrtprjs.happyexercise.service;
import com.qkrtprjs.happyexercise.dto.MemberSaveRequestDto;
import com.qkrtprjs.happyexercise.member.Member;
import com.qkrtprjs.happyexercise.member.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
@Transactional
public Long save(MemberSaveRequestDto memberSaveRequestDto) {
return memberRepository.save(memberSaveRequestDto.toEntity(memberSaveRequestDto)).getId();
}
}
해당 DTO
package com.qkrtprjs.happyexercise.dto;
import com.qkrtprjs.happyexercise.member.Member;
import com.qkrtprjs.happyexercise.member.Role;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.Column;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
@Getter
@NoArgsConstructor
public class MemberSaveRequestDto {
private String name;
private String email;
private String platform;
private String picture;
@Builder
public MemberSaveRequestDto(String name, String email, String platform, String picture, Role role) {
this.name = name;
this.email = email;
this.platform = platform;
this.picture = picture;
}
public Member toEntity(MemberSaveRequestDto memberSaveRequestDto) {
return Member.builder()
.name(memberSaveRequestDto.getName())
.email(memberSaveRequestDto.getEmail())
.platform(memberSaveRequestDto.getPlatform())
.picture(memberSaveRequestDto.getPicture())
.role(Role.USER)
.build();
}
}
만들어진 API가 이상은 없는지 테스트를 진행
테스트를 진행할때에 RANDOM_PORT 방식과 MockMvc를 사용해서 테스트를 진행하였다.
월내느 TestRestTemplate를 사용해서 테스트하려고했지만 securityConfig에서 api를 사용하기위해서는 USER라는 Role이 되어야만 실행할 수 있기때문에 @WithMockUser를 사용할 수 있는 MockMvc를 사용했다.
package com.qkrtprjs.happyexercise.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qkrtprjs.happyexercise.dto.MemberSaveRequestDto;
import com.qkrtprjs.happyexercise.member.Member;
import com.qkrtprjs.happyexercise.member.MemberRepository;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
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.boot.test.web.server.LocalServerPort;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WithMockUser(roles = "USER")
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class MemberApiControllerTest {
@LocalServerPort
private int port;
@Autowired
private MockMvc mvc;
@Autowired
private MemberRepository memberRepository;
@After
public void tearDown() throws Exception {
memberRepository.deleteAll();
}
@Test
public void member_등록() throws Exception {
//given
String name = "qkrtprjs";
String email = "qkrtprjs456";
String platform = "naver";
String picture = "picture";
MemberSaveRequestDto dto = MemberSaveRequestDto.builder()
.name(name)
.email(email)
.platform(platform)
.picture(picture)
.build();
String url = "http://localhost:" + port + "/api/member";
//when
mvc.perform(post(url)
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(dto)))
.andExpect(status().isOk())
.andDo(print());
//then
Member member = memberRepository.findAll().get(0);
assertThat(member.getName()).isEqualTo(name);
assertThat(member.getPlatform()).isEqualTo(platform);
assertThat(member.getPicture()).isEqualTo(picture);
assertThat(member.getEmail()).isEqualTo(email);
}
}
테스트 정상
다음 글에서 본격적으로 OAuth2UserService를 구현해보자!