OAuth2.0 개념
OAuth는 인터넷 사용자들이 비밀번호를 제공하지 않고 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는, 접근 위임을 위한 개방형 표준이다.
OAuth 2.0은 1.0에서 알려진 보안 문제 등을 개선한 버젼이다.
이렇게 매 사이트마다 회원가입을 할 경우
사이트의 개수만큼 내 개인정보는 많이 뿌려지고 노출되게 된다.
개인정보를 지키기에 한 곳에서 관리하는게 훨씬 더 효과적이다.
그래서 특정한 대형 포털 사이트들이 이 개인정보들을 관리하게 된다.
네이버와 카카오가 대표적이다.
이 2개의 사이트가 대표적으로 우리의 개인정보를 관리해서 로그인처리를 대신해준다.
그러니까 내가 A라는 사이트에 회원가입을 하지 않고 B라는 사이트에도 회원가입하지 않고
기존 네이버 아이디로 로그인하는 것이다.
이렇게되면 A와 B 사이트에는 내 개인정보가 없기 때문에
보안을 유지하게 위해 네이버의 개인정보만 신경쓰면 된다.
카카오가 들고 있는 다람쥐 정보에 접근할 수 있는 권한이 있다. (계정 주인이니까)
하지만 Blog 서버는 카카오가 들고 있는 다람쥐 정보에 접근할 수 있는 권한이 없다.
왜냐면 Blog 서버는 다람쥐 정보에 대한 권한이 없는 서버니까
카카오 로그인 요청을 해서 콜백으로 코드를 받았다는 것은 인증을 받았다는 것이고
AccessToken을 받았다는 것은 홍길동이 Blog 서버한테 카카오에 있는
내 정보(다람쥐 정보)에 접근할 수 있는 권한을 위임한 것이다.
다람쥐는 Blog 서버한테 내 카카오 정보에 접근할 수 있는 권한을 위임했다고 생각하면 된다.
이게 OAuth 로그인이다.
OAuth 로그인은 크게 두 가지로 생각하면 된다.
1. 첫 번째는 인증을 처리하기 위한 방법이다. (인증 처리 완료)
2. 두 번째는 인증 처리가 완료되고 나서 AccessToken을 부여 받아서 다람쥐라는 카카오 정보에
접근할 수 있는 권한을 부여할 수 있는 것이다. (권한 부여)
이 두 가지를 받는 것이 OAuth 로그인이다.
용어 정리
위 그림에서 다람쥐는 리소스 오너라고 한다.
리소스 오너라는 것은 자원 서버의 다람쥐 정보에 접근할 수 있는 주인이라는 것이다.
위 그림에서 Blog 서버는 클라이언트라고 한다.
Blog 서버는 카카오API 서버 입장에서 보면 클라이언트이기 때문이다.
(클라이언트 : 데이터를 요청하고 받는 컴퓨터)
위 그림에서 카카오 API는 인증 서버이다. 말 그대로 인증을 해주는 서버이다.
마지막으로 위 그림에서 자원을 가지고 있는 자원 서버는 리소스 서버이다.
+ 추가
스프링에서 공식적으로 지원하는 OAuth 주체는 페이스북과 구글이다.
스프링에서 스프링으로 새 프로젝트를 만들 때 OAuth2 Client를 사용할 수도 있다.
카카오 로그인 환경 설정
우선 카카오 로그인을 위해선 카카오 개발자 센터에 들어가서 애플리케이션을 등록해야 한다.
해당 링크의 카카오 개발자 센터에 들어가서
로그인 후 "내 애플리케이션"에 들어간다.
애플리케이션을 추가하였다.
들어가서 REST API키를 복사해서 메모장에 복사해두자
그리고 아래쪽에서 플랫폼 설정하기 버튼을 누른다.
Web 플랫폼 등록 버튼을 누른다.
따로 도메인을 구매하지 않았기 때문에 사용하던 localhost:8090을 입력하고 저장버튼을 누른다.
실제로 서비스할 때는 도메인을 구매 후, 그 도메인 주소를 여기다가 기입하면 된다.
왼쪽 메뉴에서 카카오 로그인을 클릭한다.
카카오 로그인을 활성화 상태로 변경해준다.
이제 그 아래에 있는 Redirect URI 등록 버튼을 눌러
카카오 로그인에서 사용할 OAuth Redirect URI를 설정한다.
Redirect URI는 나중에 카카오 로그인을 하고나서 그 로그인이 정상적으로 됐다면 응답받을 주소이다.
이 주소로 카카오측에서 정보들을 전달해준다.
왼쪽 메뉴에서 동의항목을 누르고 프로필 설정버튼을 누른다.
다음과 같이 설정한다.
로그인 시 화면을 미리보자면 다음과 같이 창이 뜬다.
사실 이 간편가입에서 이 설정을 사용하면 쉽게 기능을 구현할 수 있지만
직접 카카오 로그인 로직을 작성해보기 위해 사용하지 않을 것이다.
User 오브젝트 : id(자동으로 생성되는 번호 primary key), username, password, email 이 있다.
카카오로부터 받을 정보 : 프로필 닉네임(필수), email(선택)
카카오 로그인 인증 받기 (code)
이제 카카오 로그인 기능을 만들어보자
우선 카카오 로그인 버튼을 생성해줘야하는데 간단하게 카카오 사이트에서
카카오 버튼을 가져와 사용해보자
도구에 들어가서
리소스를 다운로드를 누르고
다운로드(.png)를 눌러 다운로드 해준다.
다운받은 파일명을 kakao_login_button으로 설정해주고
static 폴더 안에 image 폴더를 생성하고 그 안에 다운로드 받은 png파일을 넣어준다.
그리고 loginForm.jsp에 다운받은 카카오 로그인 버튼을 크기를 조절해 넣어주면
실행결과 :
다음과 같이 나타난다.
이 카카오 로그인 버튼을 눌렀을 때 어디로 갈 것인가
문서로 들어가서
스크롤을 조금 내리면 카카오 로그인에 REST API가 있다. 클릭한다.
눌러서 스크롤을 내리면 해당 URL이 뜨는데 이 링크를 카카오 로그인 버튼을 눌렀을 때의 링크로 삽입하면 된다.
이 링크는 /oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code 인데,
Host가 kauth.kakao.com니 이를 링크 앞에 붙이고, 카카오는 https 서버를 사용하니
링크는
https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code 가 되는데,
여기서 {REST_API_KEY} 자리에는 이전에 봤었던 REST API 키를 넣어주면 된다. 당연히 $ { } 다 지우고 넣어야한다.
그리고 {REDIRECT_URI}는 콜백 주소를 넣어야 한다.
이 주소를 말한다.
그렇게 완성된 해당 주소는
이 곳에 넣으면 된다.
실행결과 :
카카오 로그인 버튼을 누르면 카카오 계정 로그인창이 뜬다.
카카오 로그인 창이 뜨는데 아이디와 비밀번호를 제대로 입력하고 로그인을 누르면
동의하냐는 창이 뜨게 된다.
전체동의하고 계속하기 버튼을 눌러보면
다음 주소가 나타난다.
주소를 잘 보면 콜백 주소가 뜬다.
http://localhost:8090/auth/kakao/callback?code=otL-sxovk3RvCga-m4kPcX10XNL_QUnu1AVAOjmt8fGf-TlGzkavYXC2yrYCH3q6OJcnjQo6aVwAAARA3s176Q
이쪽 주소로 카카오가 코드를 넘겨준다.
이걸 받았다는 것은 정상적으로 로그인 인증이 됐다는 것이다.
그런데 오류가 발생하는 이유는 이 해당 주소에 대한 컨트롤러를 만들어 놓지 않았기 때문이다.
"/auth/kakao/callback"
그럼 이제 이 컨트롤러를 만들어보자
다시 실행해보자
실행결과 :
정상적으로 해당 주소에 대한 컨트롤러가 만들어 적용된 것을 확인할 수 있다.
주소를 보면 http://localhost:8090/auth/kakao/callback?code=otL-sxovk3RvCga-m4kPcX10XNL_QUnu1AVAOjmt8fGf-TlGzkavYXC2yrYCH3q6OJcnjQo6aVwAAARA3s176Q
쿼리 스트링으로 코드를 넘겨 주는 것이니까 쿼리 스트링의 값은 메서드 함수 파라미터로 쉽게 받을 수 있다.
코드를 다음과 같이 수정한다.
실행결과 :
이렇게 코드값을 받았다.
코드값을 받았기 때문에 인증은 완료된 것이다.
이제 인증된 코드 값을 통해서 AccessToken을 부여받을 것이다.
왜 AccessToken를 부여받냐면 카카오 리소스 서버에 등록된 현재 로그인한 사람의 개인정보를
응답받기 위해서이다. 그 데이터에 접근하기 위해 필요한 토큰을 부여받는 것이다.
카카오 로그인 AccessToken 받기
이제 AccessToken을 받아보자
카카오 개발자 사이트에서 문서를 클릭하고
카카오 로그인 - REST API 클릭
스크롤을 내리면 토큰 발급 요청 주소를 확인할 수 있다.
아까 전에 했던 로그인 요청 주소가 GET 방식이라면 이건 POST방식이다.
https://kauth.kakao.com/oauth/token 가 된다.
보다시피 주소로 token 뒤에 전달되는 값은 없다. 당연하지만 POST 방식이기 때문에
GET 방식처럼 쿼리스트링으로 전달하는 것이 아니라 http body에 데이터를 전달한다.
위 사진에 나와있는 대로 Content-type은 application/x-www-form-urlencoded 이다.
스크롤을 조금만 내려보면 Parameter가 보일 것이다.
이건 http body에 데이터를 전달하는데, 4가지 데이터를 담으라는 것이다.
이 때 MIME 타입이 application/x-www-form-urlencoded;charset-utf-8이라는 것은
데이터를 key=value 형태로 만들어서 전달하라는 뜻이다.
그래서 key=value 형태로 데이터를 만들어서 전달해보자
grant_type=authorization_code
client_id=e054053c94984f87d0... (앱 키 - REST API 키)
redirect_uri=http://localhost:8090/auth/kakao/callback (카카오 로그인요청 콜백 주소)
code={지금 알 수 없다. 동적임} (우리가 응답받는 code를 변수로 넣으면 된다.)
이제 UserController를 작성해보자
package com.cos.blog.controller;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import com.cos.blog.config.auth.PrincipalDetail;
// 인증이 안된 사용자들이 출입할 수 있는 경로를 /auth/**허용
// 그냥 주소가 / 이면 index.jsp 허용
// static 이하에 있는 /js/**, /css/**, /image/** 허용
@Controller
public class UserController {
@GetMapping("/auth/joinForm") // 회원가입하는데 인증필요없으므로 /auth
public String joinForm() {
return "user/joinForm";
}
@GetMapping("/auth/loginForm")
public String loginForm() {
return "user/loginForm";
}
@GetMapping("/auth/kakao/callback")
public @ResponseBody String kakaoCallback(String code) { // Data를 리턴해주는 컨트롤러 함수
// POST 방식으로 key=value 데이터를 요청 (카카오쪽으로)
// 이 때 필요한 라이브러리가 RestTemplate, 얘를 쓰면 http 요청을 편하게 할 수 있다.
RestTemplate rt = new RestTemplate();
// HTTP POST를 요청할 때 보내는 데이터(body)를 설명해주는 헤더도 만들어 같이 보내줘야 한다.
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
// body 데이터를 담을 오브젝트인 MultiValueMap를 만들어보자
// body는 보통 key, value의 쌍으로 이루어지기 때문에 자바에서 제공해주는 MultiValueMap 타입을 사용한다.
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "authorization_code");
params.add("client_id", "e054053c94984f87d0f21b0abe71d10e");
params.add("redirect_uri", "http://localhost:8090/auth/kakao/callback");
params.add("code", code);
// 요청하기 위해 헤더(Header)와 데이터(Body)를 합친다.
// kakaoTokenRequest는 데이터(Body)와 헤더(Header)를 Entity가 된다.
HttpEntity<MultiValueMap<String, String>> kakaoTokenRequest = new HttpEntity<>(params, headers);
// POST 방식으로 Http 요청한다. 그리고 response 변수의 응답 받는다.
ResponseEntity<String> response = rt.exchange(
"https://kauth.kakao.com/oauth/token", // https://{요청할 서버 주소}
HttpMethod.POST, // 요청할 방식
kakaoTokenRequest, // 요청할 때 보낼 데이터
String.class // 요청 시 반환되는 데이터 타입
);
return "카카오 토큰 요청 완료 : 토큰 요청에 대한 응답 : "+response;
}
@GetMapping("/user/updateForm")
public String updateForm(@AuthenticationPrincipal PrincipalDetail principal) {
return "user/updateForm";
}
}
실행결과 :
카카오 로그인을 할 경우 다음과 같은 응답을 받을 수 있다.
카카오 개발자 사이트에서 Response를 보면 종류를 확인할 수 있다.
이 영역을 복사해서
json parser 사이트에서 확인해보면
AccessToken을 받았다는 것을 확인할 수 있다.
이 AccessToken을 통해 Blog 서버는 카카오쪽에 저장된 회원정보에 접근할 수 있는 권한이 생겼다.
다음 시간엔 이 AccessToken으로 카카오쪽으로 카카오로 로그인한 회원의 개인정보 요청을 공부해보겠다.
학습자료 :
'자바 스프링 > 부트 블로그 JPA 프로젝트' 카테고리의 다른 글
#29 OAuth2.0과 카카오 연동 로그인2 (로그인 서비스 완료) (1) | 2022.05.18 |
---|---|
#27 회원 수정 (0) | 2022.05.17 |
#26 CRUD 게시판 - Update, Delete (수정, 삭제) (0) | 2022.05.16 |
#25 CRUD 게시판 - Read (목록,페이징,상세보기) (2) | 2022.05.16 |
#24 CRUD 게시판 - Create (글 작성하기) (0) | 2022.05.15 |