YeaLow
article thumbnail

๐ŸคREST API) ์นด์นด์˜ค ๋กœ๊ทธ์ธ API ์„œ๋น„์Šค ํ™˜๊ฒฝ์„ค์ •

 

1. ์นด์นด์˜ค ๊ฐœ๋ฐœ์ž์„ผํ„ฐ์— ์ ‘์† ํ›„ ๋กœ๊ทธ์ธํ•œ๋‹ค.

 

2. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ถ”๊ฐ€ํ•˜๊ธฐ

 

3. ์•„๋ž˜์™€ ๊ฐ™์ด ์ด๋ฆ„์„ ์„ค์ •ํ•ด์„œ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

 

4. WEB ํ”Œ๋žซํผ ๋“ฑ๋ก

 

5. ๋„๋ฉ”์ธ ๋“ฑ๋ก

 

6. ์นด์นด์˜ค ๋กœ๊ทธ์ธ ํ™œ์„ฑํ™”

 

7. Redirect URI ์„ค์ •

 

8. ๋™์˜ ํ•ญ๋ชฉ ์„ค์ •

 

9. ์ด๊ณณ์—์„œ ์นด์นด์˜ค๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค. (์ถ•์•ฝํ˜•, Middle)

 

10. ๋กœ๊ทธ์ธ ํ™”๋ฉด์— ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

<a href="#"><img height="38px"  src="/image/kakao_login_button.png"/></a>

 

11. ์นด์นด์˜ค ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” Request URI๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋งŒ๋“ค๋ฉด ๋œ๋‹ค.

GET /oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code HTTP/1.1
Host: kauth.kakao.com

REST_API_KEY๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ ํ›„ ๋ฐœ๊ธ‰๋˜๋Š” ํ‚ค๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ  REDIRECT_URI๋Š” ์œ„์—์„œ ์„ค์ •ํ•œ Redirect URI๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

 

12. ๋ฒ„ํŠผ ์ถ”๊ฐ€ ํ›„ ์‹คํ–‰์„ ํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ํ™”๋ฉด์ด ๋‚˜์˜ค๊ณ  

 

13. #์œผ๋กœ ๋น„์›Œ๋‘” <a>ํƒœ๊ทธ์— ์œ„ Request URI๋ฅผ ๋‹ด์€ ๋‹ค์Œ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์นด์นด์˜ค ๋กœ๊ทธ์ธ ํ™”๋ฉด์ด ๋‚˜์˜จ๋‹ค.


๐ŸคREST API) ์นด์นด์˜ค ๋กœ๊ทธ์ธ API ์„œ๋น„์Šค ๊ตฌํ˜„ ์™„๋ฃŒ

14. UserController์— ์นด์นด์˜ค๋กœ๊ทธ์ธ ์ฝœ๋ฐฑ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

@GetMapping("/auth/kakao/callback")
	public String kakaoCallback(String code) {
}
  • ์นด์นด์˜ค ๋กœ๊ทธ์ธ์„ ์™„๋ฃŒํ•˜๋ ค๋ฉด ์ธ๊ฐ€ ์ฝ”๋“œ๋กœ ํ† ํฐ ๋ฐœ๊ธ‰ ์š”์ฒญ์„ ํ•ด์•ผ ํ•จ.
  • ์ธ๊ฐ€ ์ฝ”๋“œ ๋ฐ›๊ธฐ๋งŒ์œผ๋กœ๋Š” ์นด์นด์˜ค๋กœ๊ทธ์ธ์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์œผ๋ฉฐ ํ† ํฐ ๋ฐ›๊ธฐ๊นŒ์ง€ ๋งˆ์ณ์•ผ ์นด์นด์˜ค ๋กœ๊ทธ์ธ์„ ์ •์ƒ์ ์œผ๋กœ ์™„๋ฃŒํ•  ์ˆ˜ ์žˆ์Œ.
  • ํ•„์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํฌํ•จํ•˜์—ฌ POST๋กœ ์š”์ฒญํ•˜๊ณ  ์š”์ฒญ ์„ฑ๊ณต ์‹œ ์•ก์„ธ์Šค ํ† ํฐ, ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ๊ณผ ํ† ํฐ ์ •๋ณด๋ฅผ ํฌํ•จํ•œ JSON๊ฐ์ฒด๋ฅผ ๋ฐ›์Œ.
  • ํ† ํฐ ๋ฐ›๊ธฐ๋ฅผ ํ†ตํ•ด ๋ฐœ๊ธ‰๋ฐ›์€ ์•ก์„ธ์Šค ํ† ํฐ์€ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ์™€ ๊ฐ™์€ ์นด์นด์˜ค ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•œ API๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์‚ฌ์šฉํ•จ.
  • ํ•ด๋‹น ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋ฐ›์•„ ์„œ๋น„์Šค ํšŒ์›๊ฐ€์ž… ๋ฐ ๋กœ๊ทธ์ธ ๋“ฑ์„ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋จ.

15. ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋Š” ๋น„ํšจ์œจ์ ์ด์ง€๋งŒ ์ข€๋” ๋ช…ํ™•ํ•˜๊ฒŒ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์ด๋ ‡๊ฒŒ ์ž‘์„ฑ.

16. ์ปจํŠธ๋กค๋Ÿฌ๋‹จ ์ „์ฒด ์ฝ”๋“œ

 

17. ์ด์ œ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ์œ„ ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌํ•ด์„œ ์กฐ๊ธˆ ์ˆ˜์ •ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

18. ๋กœ๊ทธ์ธ ํ›„ JSON์œผ๋กœ ๋ฐ˜ํ™˜๋˜๋Š” ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ JSONPOJO ์‚ฌ์ดํŠธ์— ์ ‘์†ํ•ด์„œ ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•œ ๋‹ค์Œ

 

19. ์•„๋ž˜์™€ ๊ฐ™์ด KakaoProfile ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

@Data
public class KakaoProfile {

	private Long id;
	private String connected_at;
	private Properties properties;
	private KakaoAccount kakao_account;
	
	@Data
	public class Properties {

		private String nickname;
		public String profile_image;
		public String thumbnail_image;

}
	
	@Data
	public class KakaoAccount {

		private Boolean profile_nickname_needs_agreement;
		private Profile profile;
		private Boolean has_email;
		private Boolean email_needs_agreement;
		public Boolean is_email_valid;
		public Boolean is_email_verified;
		public String email;
		
		@Data
		class Profile {

			private String nickname;
			public String thumbnail_image_url;
			public String profile_image_url;
			
		}
	}
}

20. ๋‹ค์‹œ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์™€์„œ

  • ์นด์นด์˜ค๋กœ๊ทธ์ธ์„ ํ•œ ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ๊ธฐ์กด ํšŒ์›์ธ์ง€, ์•„๋‹Œ์ง€ ์กฐํšŒ ํ›„
  • ๊ธฐ์กด ํšŒ์›์ด ์•„๋‹ ๊ฒฝ์šฐ ์ž๋™ ํšŒ์› ๊ฐ€์ž… ์ฒ˜๋ฆฌ๋˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.
  • ๊ธฐ์กด ํšŒ์›์ผ ๊ฒฝ์šฐ ์ž๋™ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌํ•˜๊ณ 
  • ๋กœ๊ทธ์ธ ํ›„์—๋Š” / ์ฃผ์†Œ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์‹œํ‚จ๋‹ค.
application.yml

cos:
  key: cos****

UserController

@Value("${cos.key")
private String cosKey;

user.java

private String oauth; //kakao, google

updateForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ include file="../layout/header.jsp"%>
<div class="container">
<!-- 	<form action="/user/join" method="post"> ์˜›๋‚  ๋ฐฉ์‹ ์‚ฌ์šฉ ์•ˆํ•จ -->
	<form>
		<input type="hidden" id="id" value="${principal.user.id}"/>
		<div class="form-group">
			<label for="username">Username</label>
			 <input type="text" value="${principal.user.username }" class="form-control" placeholder="Enter Username" id="username" readonly>
		</div>
		<c:if test="${empty principal.user.oauth }"> <!-- oauth ๊ฐ’์ด ๋น„์–ด์žˆ์ง€ ์•Š์„๋•Œ๋งŒ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ๊ฐ€๋Šฅ -->
		<div class="form-group">
			<label for="pwd">Password</label> 
			<input type="password" class="form-control" placeholder="Enter password" id="password">
		</div>
		</c:if>
		<div class="form-group">
			<label for="email">Email</label> <input type="email" value="${principal.user.email }" class="form-control" placeholder="Enter Email" id="email" readonly>
		</div>
		
		
	</form>
		<button id="btn-update" class="btn btn-primary">ํšŒ์›์ˆ˜์ •์™„๋ฃŒ</button>
</div>

<script src="/js/user.js"></script>
<%@ include file="../layout/footer.jsp"%>

UserService

package com.cos.blog.service;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
// ์Šคํ”„๋ง์ด ์ปดํฌ๋„ŒํŠธ ์Šค์บ”์„ ํ†ตํ•ด์„œ Bean์— ๋“ฑ๋ก์„ ํ•ด์คŒ . IOC๋ฅผ ํ•ด์ค€๋‹ค
import org.springframework.transaction.annotation.Transactional;

import com.cos.blog.model.RoleType;
import com.cos.blog.model.User;
import com.cos.blog.repository.UserRepository;
@Service
public class UserService {
	
	@Autowired
	private UserRepository userRepository;
	
	
	@Autowired
	private BCryptPasswordEncoder encoder;
	
	
	@Transactional
	public void ํšŒ์›๊ฐ€์ž…(User user) {
		String rawPassword = user.getPassword(); // 1234 ์›๋ฌธ
		String encPassword = encoder.encode(rawPassword); //ํ•ด์‰ฌ
		user.setPassword(encPassword);
		user.setRole(RoleType.USER);
			userRepository.save(user);
	}
	@Transactional
	public void ํšŒ์›์ˆ˜์ •(User user) {
		// ์ˆ˜์ •์‹œ์—๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ User์˜ค๋ธŒ์ ํŠธ๋ฅผ ์˜์†ํ™” ์‹œํ‚ค๊ณ , ์˜์†ํ™”๋œ User ์˜ค๋ธŒ์ ํŠธ ์ˆ˜์ •
		// select๋ฅผ ํ•ด์„œ User์˜ค๋ธŒ์ ํŠธ๋ฅผDB๋กœ ๋ถ€ํ„ฐ ๊ฐ€์ ธ์˜ค๋Š” ์ด์œ ๋Š” ์˜์†ํ™”๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ!!
		// ์˜์†ํ™”๋œ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์ž๋™์œผ๋กœDB์— update๋ฅผ ๋‚ ๋ ค์ค€๋‹ค
		User persistance = userRepository.findById(user.getId()).orElseThrow(()->{
			return new IllegalArgumentException("ํšŒ์› ์ฐพ๊ธฐ ์‹คํŒจ" );
		});
		
		// Validate ์ฒดํฌ => oauth ํ•„๋“œ์— ๊ฐ’์ด ์—†์œผ๋ฉด ์ˆ˜์ • ๊ฐ€๋Šฅ
		if(persistance.getOauth() == null || persistance.getOauth().equals("")){
			String rawPassword = user.getPassword();
			String encPassword = encoder.encode(rawPassword);
			persistance.setPassword(encPassword);
			persistance.setEmail(user.getEmail());
		}
		
		// ํšŒ์› ์ˆ˜์ • ํ•จ์ˆ˜ ์ข…๋ฃŒ์‹œ = ์„œ๋น„์Šค ์ข…๋ฃŒ = ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ = commit์ด ์ž๋™์œผ๋กœ ๋ฉ๋‹ˆ๋‹ค.
		// ์˜์†ํ™”๋œ persistance๊ฐ์ฒด์˜ ๋ณ€ํ™”๊ฐ€ ๊ฐ์ง€๋˜๋ฉด ๋”ํ‹ฐ์ฒดํ‚น์ด ๋˜์–ด update๋ฌธ์„ ๋‚ ๋ ค์คŒ
	}
	@Transactional
	public User ํšŒ์›์ฐพ๊ธฐ(String username) {
		User user = userRepository.findByUsername(username).orElseGet(()->{
			return new User();
		});
		return user;
	}
}
//	@Transactional(readOnly = true) // Select ํ•  ๋•Œ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘, ์„œ๋น„์Šค ์ข…๋ฃŒ์‹œ์— ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ (์ •ํ•ฉ์„ฑ)
//	public User ๋กœ๊ทธ์ธ(User user) {
//		return userRepository.findByUsernameAndPassword(user.getUsername(), user.getPassword());
//	}
	
//	@Transactional
//	public int ํšŒ์›๊ฐ€์ž…(User user) {
//		try {
//			userRepository.save(user);
//			return 1;
//		} catch (Exception e) {
//			e.printStackTrace();
//			System.out.println("UserService : ํšŒ์›๊ฐ€์ž…() : " + e.getMessage());
//		}
//		return -1;
//	}
		// User ์˜ค๋ธŒ์ ํŠธ : username, password, email
		System.out.println("์นด์นด์˜ค ์•„์ด๋””(๋ฒˆํ˜ธ) : " + kakaoProfile.getId());
		System.out.println("์นด์นด์˜ค ์ด๋ฉ”์ผ : " + kakaoProfile.getKakao_account().getEmail());
		
		System.out.println("๋ธ”๋กœ๊ทธ์„œ๋ฒ„ ์œ ์ €๋„ค์ž„ : "+kakaoProfile.getKakao_account().getEmail()+"_"+kakaoProfile.getId());
		System.out.println("๋ธ”๋กœ๊ทธ์„œ๋ฒ„ ์ด๋ฉ”์ผ : "+kakaoProfile.getKakao_account().getEmail());
		// UUID๋ž€ -> ์ค‘๋ณต๋˜์ง€ ์•Š๋Š” ์–ด๋–ค ํŠน์ • ๊ฐ’์„ ๋งŒ๋“ค์–ด๋‚ด๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜
		System.out.println("๋ธ”๋กœ๊ทธ์„œ๋ฒ„ ํŒจ์Šค์›Œ๋“œ : "+cosKey);
		
		User kakaoUser = User.builder()
				.username(kakaoProfile.getKakao_account().getEmail()+"_"+kakaoProfile.getId())
				.password(cosKey)
				.email(kakaoProfile.getKakao_account().getEmail())
				.oauth("kakao")
				.build();
		
		// ๊ฐ€์ž…์ž ํ˜น์€ ๋น„๊ฐ€์ž…์ž ์ฒดํฌ ํ•ด์„œ ์ฒ˜๋ฆฌ
		User originUser = userService.ํšŒ์›์ฐพ๊ธฐ(kakaoUser.getUsername());

		if(originUser.getUsername() == null) {
			System.out.println("๊ธฐ์กด ํšŒ์›์ด ์•„๋‹ˆ๊ธฐ์— ์ž๋™ ํšŒ์›๊ฐ€์ž…์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค");
			userService.ํšŒ์›๊ฐ€์ž…(kakaoUser);
		}
		
		System.out.println("์ž๋™ ๋กœ๊ทธ์ธ์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.");
		// ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ
		Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(kakaoUser.getUsername(), cosKey));
		SecurityContextHolder.getContext().setAuthentication(authentication);
		
		return "redirect:/";โ€‹

 

์ฒ˜์Œ Kakao API๋ฅผ ํ•ด๋ดค๋‹ค.. ์ •๋ง ํ—ท๊ฐˆ๋ฆฌ๊ณ  ๊ณ ์น ๊ป˜ ๋งŽ์•„์„œ ํž˜๋“ค์—ˆ๋‹ค. 

์ฝ”๋“œ๋ฅผ ๋‹ค ๊ณ ์ณค๋Š”์ง€๋Š” ๋ชจ๋ฅด์ง€๋งŒ ํ•œ๋ฒˆ ํ•„์š”ํ•˜์‹œ๋ฉด ๋“ค๊ณ ๊ฐ€์„œ ํ•ด๋ณด์…”์š”

profile

YeaLow

@YeaLow

ํฌ์ŠคํŒ…์ด ์ข‹์•˜๋‹ค๋ฉด "์ข‹์•„์š”โค๏ธ" ๋˜๋Š” "๊ตฌ๋…๐Ÿ‘๐Ÿป" ํ•ด์ฃผ์„ธ์š”!