해당글은 개인적인 공부 리뷰용입니다.
생활코딩의 OAuth강의를 정리했다고 보시는게 가장 정확합니다
=======================
왜 OAuth2.0을 공부해야 하냐고 물어보면은...
소셜로그인을 구현을 하고 싶어서다
내 사이트가 너무나 거대해져서, 나만의 로그인 시스템을 제공해줄수 있는 상황이 아니라면,
아무래도 나의 조그마한 사이트에서는 구글이나 페이스북, 네이버가 제공을 해주는 OAuth 로그인을 사용을 할 것이다.
그렇기 때문에 나에게는 OAuth가 필요하다
전반적인 나의 스펙을 살펴보면은
fastapi+ nextjs로 사이트를 구성을 하고, 거기에다 네이버 로그인을 붙일 예정이다.
해당 여정은 위에 대한 것들을 나타내는 것을 그 골자로 한다.
먼저 OAuth에 대해서 알아보고 가자.
==============================
OAuth는 3자대면 작업이다.
슈퍼K라는 나의 사이트가 있다고 가정하자.
그 사이트에서는 네이버 로그인을 사용을 해서 사용자인증을 진행한다.(federate identity)
그리고 우리 사이트를 이용하는 유저들도 존재한다.
OAuth 에서는
슈퍼K라는 우리 사이트를 Client라고 (Resource Server 에게 자원을 요구하는 손님이라는 뜻)
네이버 를 Resource Server(or Authorization Server)라고 부른다.
(우리가 사용하고자 하는 자원(로그인자원)을 가지고 있다고 해서)
우리사이트 유저를 Resource Owner라고 한다.(리소스를 소유한 주인이라고 해서)
---------------
등록(register)
맨처음에 우리가 OAuth를 사용하기 위해서는 등록을 진행을 먼저 해야한다.
흔히들 아래와 같은 정보를 얻기 위한 과정인데,
이는 흔히 OAuth를 구현하려는 사이트에서 얻기 쉬운 부분이다
네이버 로그인에서는 아래에 들어가면 등록과정을 진행을 할 수가 있다
https://developers.naver.com/main/
각 항목을 작성을 하고 나면은
네이버에서 Client ID 와 Client Secret를 제공해준다.
ClientID는 외부에 공개가 되어도 괜찮으나,
Client Secret은 외부에 공개가 되면 곤란하다...
그리고 Authorized redirect URIs는 우리가 지정을 해주는 것인데,
네이버가 우리에게 Authorized code를 전달해주는 과정이 있는데,
그 코드를 우리가 지정한 Authorized redirect URI로 전달을 해준다.
이 부분을 기억을 해두고, 추후에 나오는 부분에서 연관되어 생각을 해보자.
====================
Resource Owner의 승인
현재까지 우리가 알고있는 것은 아래의 그림과 같다.
나의 사이트와 네이버는
Client ID와 Client Secret, 그리고 redirect URL을 알고 있는 상황이다.
우리는 네이버의 로그인기능만 필요하다. 딱 그 기능만 허락을 받으면 되는 상황이다.
우리 우리사이트 이용자(Resource Owner)가 등장하는 차례이다.
등장은 어떻게 하냐???
이렇게는 아니고 ㅋㅋㅋㅋㅋ
우리는 우리나름의 방식으로 등장을 한다
네이버는 네이버 방식으로 등장을 하면된다
버튼으로 등장 그리고 그 버튼에는 링크가 달려있는데,
http://resource.server?client_id=1&scope=B,C&redirect_uri=https://client/callback
이라는 링크로 가게끔 해주면 된다
링크로 가면은
네이버(Resource Server)는 우리사이트 사용자(Resource owner)에게 권한을 요청한다.
아래와 같은 화면으로 흔히들 봤겠지요?ㅎㅎㅎㅎ
=====================
Resource Server의 승인
여기까지의 상황은 다음의 그림에서 나타난다.
네이버(Resource Server) 는 우리 사이트에 들어온 유저(Resource Owner)가 권한을 요청하였고,
로그인 권한(여기서는 scope:b,c)를 허락해주었다 라는 것까지가 현재 단계이다.
이제 여기서 네이버는 authorization code라는 것을 발급해서,
그것을 우리사이트 유저(Resource Owner)에게 전달을 해준다...
그런데 그냥 전달해주는것이 아니라,
Location Header에 넣어서 전달을 해주기때문에,
우리 사이트 유저(Resource Owner)는 https://client/callback?code=3이라는 곳으로
자기도 모르는 사이에 redirect 되게끔 된다......
그렇게 리다이렉트 되는 주소가 어디????
바로 우리가 처음에 authorized redirect uri 라고 써져있는 곳으로
쿼리스트링에 authorization 코드가 들어가진체로 전달이 된다...
그러면 우리(client,슈퍼K 사이트 서버)는
사이트 이용자(Resource Owner)를 통해서 authorization code를 알게되었다
이렇게되면은
네이버와 우리사이트 사용자 사이에 은밀한하게 전달된 내용인 (Authorization code)를
우리(슈퍼K 사이트 운영서버)도 알게되었다...ㅎㅎㅎ
너네가 알고 있는것을 나도 알게 되었으니,
나도 믿을수 있는 녀석이다!!! 라는 것을 이제 네이버에게 다시 알려줘야 하는데,
그렇게 하기 위해서는
우리는 다시 네이버 서버로 아래와 같은 요청을 보내면 된다.
https://resource.server/token?grant_type=authorization_code&code=3&redirect_uri=https://client/callback&client_id=1&client_secret=2
여기서 우리가 주의깊게 봐야하는 부분은
빨간색으로 강조한 code 부분과 client_secret이다.
code가 3이라는 것은 우리 사이트 유저인 resource owner랑 우리사이트(슈퍼k)가 제대로 믿을수 있는 사이라는 것이고,
client_secret은 우리가 제일처음에 네이버 사이트에 등록하고 받은 비밀서약인데,
그 두개의 정보와 redirect_uri를 통해서,
우리사이트 + 네이버 + 우리사이트 유저 , 이렇게 3자간은 믿을수 있는 동맹관계라는 것을 제대로 알려주는 것이다.
이제 이렇게 신원이 확실하게 되면은
네이버는 우리에게 액세스 토큰을 발급해주는것이다.
이제 우리도 nextjs에랑 fastapi로 로그인 기능을 구현을 해보자!!!!!!!!!!
nextjs 에는 next-auth.js라는 좋은 라이브러리도 있지만,,,
나같이 서버는 다르게 이용하고자 하는 사람에게는 사용이 가능한지는 알아보지는 않았다.
그런데 next-auth로 구현을 했을때에는
내가 밑바닥부터 해당 로그인을 구현했다는 느낌이 전혀없었다....
그냥 라이브러리를 사용만 한다는 느낌.
그래서 한번은 밑에서부터 만들어봐야 된다는 생각이었다.
내가 좋아하는 스택으로 만들기를 시작할련다
NextJS에서 로그인 버튼 만들기
먼저 새로운 nextjs 프로젝트를 생성을 해보자.
초기세팅값은 아래와 같이 선택을 하였다.
아래가 무슨 말인지 모르겠으면,,,,nextjs 기초부터 공부하고 오시길 바랍니다.
npx create-next-app@latest --experimental-app
global.css,page.module.css 전부 깨끗하게 지우고 시작을 합니다.
page.js는 div박스와 버튼을 만들어 놔두었습니다.
그리고 버튼을 눌렀을때에 필요한 링크를 적용해줍니다.
아래와 같이 적용을 해보았습니다.
'use client'
import React from "react";
export default function Naver() {
let request_url = "https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id={네이버에서 발급받은 클라이언트id}&redirect_uri=http://localhost:3000/callback"
return (
<div>
<h1>My Page</h1>
<button>
<a href={request_url}>네이버 로그인</a>
</button>
</div>
);
}
딱 아래와 같은 상황입니다. 버튼을 누르면 https://resource.server?client_id=1&scope=B,C&redirect_uri=https://client/callback 이라는 곳으로 보내주는것을 위에서는 request_url안에 담아 보았습니다.
아래와 같은 next.js로 만든 페이지에서
버튼을 눌러봅니다.
callback페이지도 next.js에다 만들어줬습니다...
localhost:3000/callback 으로 요청하면, 해당 페이지가 나오게 만들어주시면 됩니다.
이정도는 할 줄 아시져??
그랬더니 해당 url에 쿼리스티링으로 code가 같이 딸려옵니다!!!!!
어때요??ㅎㅎ
차근차근 딱딱 되어가는것이 느껴집니다
그리고 이렇게 callback받은 code를 포함하여,
다시 access_token을 요청을 하는 url을 만들어서 네이버서버로 보내주면, 딱 완성이 되겠지요?
자..
이제 fastapi 서버를 이용해서 한번 진행을 해보도록 합시다!
callback서버를 http://localhost:8080/callback으로 진행을 하고 우리가 원하는 정보를 가져와봅도록 합시다
fast api로 다음과 같이 api를 만들었습니다.
@app.get("/callback")
async def callback(code):
client_id = "발급받은 client_id"
client_secret = "발급받은 client_secret"
redirect_uri = "http://localhost:8080/callback"
token_request = requests.get(f"https://nid.naver.com/oauth2.0/token?grant_type=authorization_code&client_id={client_id}&client_secret={client_secret}&code={code}")
token_json = token_request.json()
print(token_json)
access_token = token_json.get("access_token")
profile_request = requests.get("https://openapi.naver.com/v1/nid/me", headers={"Authorization" : f"Bearer {access_token}"},)
profile_data = profile_request.json()
print(profile_data)
return RedirectResponse('http://localhost:3000/callback')
그리고 나서 우리가 처음에 만들었던 네이버로그인 버튼의 callback uri를 fastapi의 callback 앤드포인트로 바꿔줍니다.
fastapi서버에서 로그인된 아이디의 profile 데이터를 가지고 와준다.
이것으로 데이터 가져오기 끝!!!!
로그인 세부적인 사항들은 각 프로젝트에 따라 구현을 해보면되겠다
아래는 네이버 로그인 SDK에 관한 내용들이다.
필요하신 분들은 한번 참고하시면 좋겠다.
네이버 로그인 SDK를 사용하기
네이버 로그인 개발문서는 다음의 링크에 있습니다.
https://developers.naver.com/docs/login/devguide/devguide.md#1--개요
네이버 로그인 버튼을 넣고싶은 페이지에 아래와 같이 코드를 작성을 해준다.
무슨 이유에서인지 layout.js에 head에 스크립트를 추가하려고 하니깐,
window.naver객체를 읽어들이지 못하더라....
그런데 해당 페이지에 진행을 하니깐 제대로 되네.... 왜 그런걸까???
'use client'
import React, { useState, useEffect } from "react";
export default function Home() {
useEffect(() => {
initNaverLogin();
getData();
}, []);
// console.log(window);
const getData = (r) => {
console.log(r);
if (window.location.href.includes("access_token")) {
console.log("We got AccessToken");
}
};
const initNaverLogin = () => {
const naverLogin = new window.naver.LoginWithNaverId({
clientId: "네이버에서 발급해준 Client Id",
callbackUrl: "http://localhost:8080/callback",
isPopup: false,
loginButton: { color: "green", type: 3, height: 60 },
callbackHandle: true,
});
naverLogin.init();
getData();
}
return (
<div>
<script
defer
type="text/javascript"
src="https://static.nid.naver.com/js/naveridlogin_js_sdk_2.0.2.js"
/>
<div id="naverIdLogin" />
</div>
);
}