세번째 기능은 타인이 보는 나의 향수이다.
"나의 향수를 추천해줘"라는 링크를 타인에게 공유하고, 타인은 해당 링크에 접속하여, 첫번째 기능과 유사한 설문을 진행하고, 나는 타인이 추천해준 향수들을 조회할 수 있다.
이 기능은 로그인이 반드시 필요한 기능이기 때문에, 카카오 로그인을 사용하였다.
로그인 부분은, 아직 저에게 많이 어려운 주제라, 중간 중간 틀린 부분이 있을 수 있습니다 ㅜ.. 참고만 해주세요 !
일단은 우리 서비스의 특성도 고려해야 한다. 우리 서비스는 MBTI 검사 서비스처럼, 한 사용자가 지속적으로 사용하는 서비스가 아니라, 여러 사용자가 가볍게 사용할 수 있는 서비스라고 생각한다.
3번째 서비스를 이용하는 사용자는 링크를 공유하여 친구들에게 추천을 받을 것이다. 사용자는 일정 시간마다 접속하여 타인이 추천해준 향수 결과를 확인할 것이다.
나중에 배포하고 로그를 봐야 알겠지만, 대략 30분~1시간 주기로 확인을 할 것이라고 예상이 된다.
그렇기 때문에 AccessToken의 만료 시간을 30분~1시간 정도로 설정을 할 예정이다.
RefreshToken은 일반적으로 2주정도의 기간으로 설정한다고 알고있다. 우리 서비스는 지속적인 서비스가 아닌 가볍게 사용하는 서비스이기 때문에, 일반적인 기준에 따라 기간을 설정할 예정이다.
OauthType.java
@Getter
public enum OauthType {
CONTENT_TYPE("Content-type","application/x-www-form-urlencoded;charset=utf-8"),
GRANT_TYPE("grant_type","authorization_code"),
CLIENT_ID("client_id","RESTAPI 주소!"),
REDIRECT_URI("redirect_uri","Redirect URI");
private String name;
private String type;
OauthType(String name, String type) {
this.name = name;
this.type = type;
}
}
사용될 RestApi 주소와 상수들을 관리하는 Enum객체를 생성하였다.
OauthService.java
@Service
public class OauthService {
private final MemberService memberService;
private OauthService(MemberService memberService) {
this.memberService = memberService;
}
private HttpHeaders setHttpHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(OauthType.CONTENT_TYPE.getName(), OauthType.CONTENT_TYPE.getType());
return httpHeaders;
}
private LinkedMultiValueMap<String, String> setHttpBody(String code) {
LinkedMultiValueMap<String, String> accessTokenParams = new LinkedMultiValueMap<>();
accessTokenParams.add(OauthType.GRANT_TYPE.getName(), OauthType.GRANT_TYPE.getType());
accessTokenParams.add(OauthType.CLIENT_ID.getName(), OauthType.CLIENT_ID.getType());
accessTokenParams.add(OauthType.REDIRECT_URI.getName(), OauthType.REDIRECT_URI.getType());
accessTokenParams.add("code", code);
return accessTokenParams;
}
private RestTemplate createRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
return restTemplate;
}
//여기까지 토큰 값 받기
public ResponseEntity<String> getResponseFromServer(String url, String code, HttpHeaders httpHeaders) {
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>((setHttpBody(code)), httpHeaders);
ResponseEntity<String> response = createRestTemplate().exchange(url, HttpMethod.POST, request, String.class);
return response;
}
public Member loadUserProfile(String code, HttpSession httpSession) {
try {
JSONParser jsonParser = new JSONParser();
HttpHeaders httpHeaders = setHttpHeaders();
JSONObject jsonObject = (JSONObject) jsonParser.parse(getResponseFromServer("https://kauth.kakao.com/oauth/token", code, httpHeaders).getBody());
httpSession.setAttribute("Authorization", jsonObject.get("access_token"));
httpHeaders.add("Authorization", "Bearer " + jsonObject.get("access_token"));
ResponseEntity<String> responseEntity = getResponseFromServer("https://kapi.kakao.com/v2/user/me", code, httpHeaders);
JSONObject profile = (JSONObject) jsonParser.parse(responseEntity.getBody());
JSONObject properties = (JSONObject) profile.get("properties");
JSONObject kakaoAccount = (JSONObject) profile.get("kakao_account");
MemberRequestDto memberRequestDto = MemberRequestDto.builder()
.memberId((Long) profile.get("id"))
.nickname((String) properties.get("nickname"))
.email((String) kakaoAccount.get("email"))
.thumbnailImage((String) properties.get("thumbnail_image"))
.build();
saveUserProfile(memberRequestDto);
return memberService.findByMemberPk(memberRequestDto.getMemberId());
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public void saveUserProfile(MemberRequestDto memberRequestDto) {
Member member = Member.builder()
.memberId(memberRequestDto.getMemberId())
.email(memberRequestDto.getEmail())
.memberId(memberRequestDto.getMemberId())
.nickname(memberRequestDto.getNickname())
.thumbnailImage(memberRequestDto.getThumbnailImage())
.build();
isAgreeEmailUsing(memberRequestDto.getEmail());
if (!memberService.isAlreadyExistMember(memberRequestDto)) {
memberService.saveMemberProfile(member);
}
}
public boolean isAgreeEmailUsing(String email) {
if (email == null) {
throw new EmailNotFoundException();
}
return true;
}
}
OauthController.java
@RestController
@RequestMapping("/oauth")
public class OauthController {
private final OauthService oauthService;
private final LoginService loginService;
public OauthController(OauthService oauthService, LoginService loginService) {
this.oauthService = oauthService;
this.loginService = loginService;
}
@GetMapping("/login")
public ResponseEntity<LoginResponse> signUp(@RequestParam String code, HttpSession httpSession) {
Member member = oauthService.loadUserProfile(code, httpSession);
return ResponseEntity.ok(loginService.generateToken(member.getMemberId()));
}
다음 글에서 Jwt를 활용할 것이다.
이미지 출처
padd60님의 카카오 로그인 뿌수기