이번 프로젝트에서는 웹 서비스와 카카오 소셜로그인을 구현해볼것이기 때문에 카카오를 기준으로 다음 인증과정을 진행해보겠다.
우선 kakao developers에서 회원가입, 로그인을 진행한 후 내 애플리케이션으로 들어간다.
Flask 객체를 불러오는 메인 모듈이다.
kakao api blueprint를 등록시킨다.
위의 Kakao Developers에서 발급받은 정보를 저장한다.
CLIENT_ID = REST API Key
CLIENT_SECRET = 카카오 로그인 > 보안에서 발급받은 Client Secret
REDIRECT_URI = 카카오 로그인 기능을 위해 설정한 Redirect URI
SIGNOUT_REDIRECT_URI = 카카오 로그인 > 고급에서 발급받은 카카오 계정과 함께 로그아웃 기능을 위해 설정한 Logout Redirect URI
Oauth 객체를 정의한다.
import requests
from key.kakao_client import CLIENT_ID, CLIENT_SECRET, REDIRECT_URI
class Oauth:
def __init__(self):
self.auth_server = "https://kauth.kakao.com%s"
self.api_server = "https://kapi.kakao.com%s"
self.default_header = {
"Content-Type": "application/x-www-form-urlencoded",
"Cache-Control": "no-cache",
}
def auth(self, code):
return requests.post(
url=self.auth_server % "/oauth/token",
headers=self.default_header,
data={
"grant_type": "authorization_code",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"redirect_uri": REDIRECT_URI,
"code": code,
},
).json()
def userinfo(self, bearer_token):
return requests.post(
url=self.api_server % "/v2/user/me",
headers={
**self.default_header,
**{"Authorization": bearer_token}
},
# "property_keys":'["kakao_account.profile_image_url"]'
data={}
).json()
카카오 로그인과 관련된 api를 작성한다.
| method | parameters | return | 내용 |
|---|---|---|---|
| GET | - | redirect to 홈페이지 | 카카오 사용자 로그인 |
@kakao.route('/')
def kakao_sign_in():
# 카카오톡으로 로그인 버튼을 눌렀을 때
kakao_oauth_url = f"https://kauth.kakao.com/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code"
return redirect(kakao_oauth_url)
@kakao.route('/callback')
def callback():
code = request.args["code"]
# 전달받은 authorization code를 통해서 access_token을 발급
oauth = Oauth()
auth_info = oauth.auth(code)
# error 발생 시 로그인 페이지로 redirect
if "error" in auth_info:
print("에러가 발생했습니다.")
return {'message': '인증 실패'}, 404
# 아닐 시
user = oauth.userinfo("Bearer " + auth_info['access_token'])
print(user)
kakao_account = user["kakao_account"]
profile = kakao_account["profile"]
name = profile["nickname"]
if "email" in kakao_account.keys():
email = kakao_account["email"]
else:
email = f"{name}@kakao.com"
user = User.query.filter(User.name == name).first()
if user is None:
# 유저 테이블에 추가
user = User(name, email, generate_password_hash(name))
db.session.add(user)
db.session.commit()
# message = '회원가입이 완료되었습니다.'
# value = {"status": 200, "result": "success", "msg": message}
session['email'] = user.email
session['isKakao'] = True
# message = '로그인에 성공하였습니다.'
# value = {"status": 200, "result": "success", "msg": message}
return redirect("http://localhost")
카카오톡 로그인 시 카카오 유저인지 정보를 세션에 담아뒀다가 카카오 로그인 사용자가 로그아웃을 할 경우 oauth/kakao/signout api를 호출하여 카카오 계정과 함께 로그아웃이 가능하도록 한다.
| method | parameters | return | 내용 |
|---|---|---|---|
| GET | - | redirect to 홈페이지 | 카카오 사용자 로그아웃 |
@kakao.route('/signout')
def kakao_sign_out():
# 카카오톡으로 로그아웃 버튼을 눌렀을 때
kakao_oauth_url = f"https://kauth.kakao.com/oauth/logout?client_id={CLIENT_ID}&logout_redirect_uri={SIGNOUT_REDIRECT_URI}"
if session.get('email'):
session.clear()
value = {"status": 200, "result": "success"}
else:
value = {"status": 404, "result": "fail"}
print(value)
return redirect(kakao_oauth_url)
로그인 버튼 클릭시 요청하는 api는 redirect를 시켜주는 역할을 하기 때문에 비동기 통신(axios) 방식으로 호출하면 안된다.
따라서 리다이렉트 받을 수 있도록 html 링크로 구현하거나, JavaScript SDK를 사용하여야 한다.
따라서 원래는 기존 홈페이지 기능에 있는 기본 로그인 기능 처럼 성공/실패 여부를 객체로 return 하려 했는데 그 대신 리턴값을 홈페이지로 redirect 하는 것으로 바꾸고 프론트단에서는 html 링크로 구현하는 방식으로 진행하였다.
표준 디자인 규격이 있으니 참고하자!
카카오 로그인 버튼 디자인 가이드