[KISA 핀테크 기술지원센터] 기술세미나 :: 구글 로그인 연동으로 배우는 OAuth 인증 - 2
OAuth과정
Client가 Resource Server에게 '기능 좀 쓰자' 요청
Resource Server가 Client에게 Client_id 와 Client_Secret을 발급
Client는 별도의 저장소에 발급받은 Client_id 와 Client_Secret을 저장해둠
Resource Owner가 Resource Server에게 다음과 같은 메시지 요청
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly& include_granted_scopes=true& state=state_parameter_passthrough_value& redirect_uri=http%3A%2F%2Foauth2.example.com%2Fcallback& response_type=token& client_id=client_id // client_id에 해당하는 어플리케이션에서 scope에 해당하는 기능만 좀 쓰자 // Access Token은 redirect_uri 주소로 보내줘
Resource Server가 Resource Owner에게 해당 기능에 대한 권한을 허용할 것인지 물어봄 (Consent Screen)
허용하면 Resource Server가 redirect_uri에 해당하는 Client에 Access Token을 배달해줌
6번까지 끝낸다음 다시 로그인을 해보면 url에 다음과 같은 정보가 담겨온다.
http://localhost:8887/raw_callback.html#state=state_parameter_passthrough_value&access_token=엑세스토큰정보&expires_in=3600&scope=email%20profile%20https://www.googleapis.com/auth/calendar%20https://www.googleapis.com/auth/userinfo.email%20openid%20https://www.googleapis.com/auth/userinfo.profile&authuser=0&session_state=5b0d22941eafc63b8e97c7ffdc85cef0f57aac3c..1765&prompt=none
#: 영향을 주지않는
- cf : ? 로 쓰면 실제 데이터를 전달함 (서비스에 영향을 줌)
state : 우리가 준거를 그대로 뱉어냄. 이것을 보고 정말 제대로 된 정보를 받았는지 검증할 수 있음
요청은 하지 않았지만 기본적으로 가지는 scope도 있다.
번외
URI에서 Access Token만 뽑아내는 법
- 정규화 이용
raw_callback.html 생성 후 다음과 같이 작성
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h1>Access Token</h1>
<script>
var at = location.href.match('access_token=(.+?)&')[1];
document.write(at);
</script>
</body>
</html>
정규화에 대한 부가 설명은 생략하도록 한다.
https://www.googleapis.com/oauth2/v1/userinfo?alt=json 접속하면
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
다음과 같이 인증할 수 없다고 나옴.
거의 다왔다!
url 파라미터에 우리의 Access_Token을 넣어주면?
https://www.googleapis.com/oauth2/v1/userinfo?alt=json?access_token=엑세스토큰
{
"id": "2222222222222222",
"email": "test@naver.com",
"verified_email": true,
"name": "성건희",
"given_name": "건희",
"family_name": "성",
"link": "https://plus.google.com/2222222222222222222",
"picture": "https://lh4.googleusercontent.com/-d6_wviRTtng/DDDDDDAAAI/DDDGKs/iF12Fb-2Bwk/photo.jpg",
"locale": "ko"
}
내 소중한 정보를 볼 수 있다.
하지만 URL 상에 Access Token을 보내는 방식은 보안상 좋지 않다.
# library 방식
구글 OAuth 메뉴얼의 Complete Example 코드를 복사 후 lib.html 생성 후 붙여넣는다.
Client_id 와 SCOPE를 수정해준다.
<script>
var GoogleAuth;
var SCOPE = 'https://www.googleapis.com/auth/calendar';
function handleClientLoad() {
// Load the API's client and auth2 modules.
// Call the initClient function after the modules load.
gapi.load('client:auth2', initClient);
}
function initClient() {
// Retrieve the discovery document for version 3 of Google Drive API.
// In practice, your app can retrieve one or more discovery documents.
var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';
// Initialize the gapi.client object, which app uses to make API requests.
// Get API key and client ID from API Console.
// 'scope' field specifies space-delimited list of access scopes.
gapi.client.init({
'apiKey': 'YOUR_API_KEY',
'discoveryDocs': [discoveryUrl],
'clientId': '898088711348-0bg7rc6abjssqiitkecq50tmnmq65ls0.apps.googleusercontent.com',
'scope': SCOPE
}).then(function () {
GoogleAuth = gapi.auth2.getAuthInstance();
// Listen for sign-in state changes.
GoogleAuth.isSignedIn.listen(updateSigninStatus);
// Handle initial sign-in state. (Determine if user is already signed in.)
var user = GoogleAuth.currentUser.get();
setSigninStatus();
// Call handleAuthClick function when user clicks on
// "Sign In/Authorize" button.
$('#sign-in-or-out-button').click(function() {
handleAuthClick();
});
$('#revoke-access-button').click(function() {
revokeAccess();
});
});
}
function handleAuthClick() {
if (GoogleAuth.isSignedIn.get()) {
// User is authorized and has clicked 'Sign out' button.
GoogleAuth.signOut();
} else {
// User is not signed in. Start Google auth flow.
GoogleAuth.signIn();
}
}
function revokeAccess() {
GoogleAuth.disconnect();
}
function setSigninStatus(isSignedIn) {
var user = GoogleAuth.currentUser.get();
var isAuthorized = user.hasGrantedScopes(SCOPE);
if (isAuthorized) {
$('#sign-in-or-out-button').html('Sign out');
$('#revoke-access-button').css('display', 'inline-block');
$('#auth-status').html('You are currently signed in and have granted ' +
'access to this app.');
} else {
$('#sign-in-or-out-button').html('Sign In/Authorize');
$('#revoke-access-button').css('display', 'none');
$('#auth-status').html('You have not authorized this app or you are ' +
'signed out.');
}
}
function updateSigninStatus(isSignedIn) {
setSigninStatus();
}
</script>
<button id="sign-in-or-out-button"
style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
style="display: none; margin-left: 25px">Revoke access</button>
<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
OAuth의 승인 방식 종류
여러가지 승인 방식이 있지만 대표적인 2가지만 소개
- Implicit Grant Type : 암시적 승인
- 우리가 지금까지 실습해온 방식
- 위험함 (OAuth 공식 메뉴얼에서도 추천하지 않음)
- Authorization Code Grant Type : 권한 부여 코드 승인 타입
- Resource Server가 Client에게 Access Token을 주지 않고 CODE라는 녀석을 줌
- Client가 Resource Server에게 정보를 제출 : Client_id, Client_secret, CODE
- 그 뒤 Resource Server가 일치하는지 판별 후 일치하면 Access Token을 전송
'세미나' 카테고리의 다른 글
[기술교육] JPA 트러블 슈팅 - 1편 (1) | 2023.03.14 |
---|---|
if Kakao dev 2020 - 카카오 대 장애 회고 정리 (2) | 2022.12.07 |
코드리뷰 노하우 (0) | 2022.08.12 |
구글 로그인 연동으로 배우는 OAuth 인증 - 1 (2) | 2019.05.14 |
카카오 세미나 (0) | 2019.03.05 |
댓글