지난 프로젝트 때는 express 서버에서 github 소셜로그인을 구현했다면, 이번 프로젝트에서는 python flask로 소셜로그인을 구현해보았다.
전반적인 통신 과정, 원리는 비슷하므로 이번 게시글에서는 카카오 유저 등록 및 코드 구현 위주로 정리하려 한다.
소셜로그인 원리에 대한 이해는 해당 게시글을 참고,
실제 구현 과정에서의 방식에 대한 이해를 하려면 이 게시글을 참고하면 된다.
카카오에 개발자 등록하기
카카오 개발자 콘솔 로 접속하여 애플리케이션을 생성하고 아래와 같이 clientID, clientSecret, redirect path 를 설정합니다.
a. 메인 페이지의 시작하기로 들어가기
b. 내 애플리케이션 추가하기 진행하기
-> 아이콘은 아직 나오지 않아서 미등록했는데도 추가가 됐다.
-> 사업자 이름 입력하라해서 당황했는데 우리 팀명을 입력했는데도 큰 문제가 없었다.
c. 등록한 서비스를 클릭해준 다음에
1. 화면의 카카오 로그인->동의항목으로 가주기
2. 개인정보 보호에서 아래화면처럼 설정버튼이 활성화된 정보들에 대해서 공개 여부를 지정해줘야 한다.
-> 동의 항목 설정을 누르면 아래와 같은 창이 뜬다. / 처음에는 이메일 값을 필수로 진행하려 했으나, 아래 창과 같이 검수가 필요하다고 하여, 개인 프로필을 구분자로 사용하기 위해 필수동의로 활용했다.
아직 스터디 단계의 프로젝트이므로 민감한 개인정보에는 보수적으로 접근하기로 했다.
d. 다시 카카오 로그인 탭으로 가서 해당 화면처럼 활성화 설정 부분이 off로 되어있다면, on으로 바꿔준다.
e. 하단의 redirect URL 입력 칸에 소셜로그인 성공 시에 다시 돌아올 주소를 입력한다.
-> 해당 주소의 규칙은 보통 " 도메인 주소/ 개인 프로젝트에서 소셜로그인 api / callback
아래의 앱키들이 바로 일종의 clinetID 역할을 하는 것이다.
- 네이티브 앱 키: Android, iOS SDK에서 API를 호출할 때 사용합니다.
- JavaScript 키: JavaScript SDK에서 API를 호출할 때 사용합니다.
- REST API 키: REST API를 호출할 때 사용합니다.
- Admin 키: 모든 권한을 갖고 있는 키입니다. 노출이 되지 않도록 주의가 필요합니다.
-> 여기서 각 키의 의미를 잘 고민해 보아야 한다. 이에 따라 코드 로직이 달라진다.
각 키에 대한 설명은 다른 게시글에 정리해두었으니 참고!
내가 참고한 해당 블로그에도 적어두었듯이, 우리는 expo eject를 하면서 까지 네이티브 SDK를 사용할 필요가 없기 때문에 javascript키와 REST API 키 중에서 고민하였고, 시간적인 이유로 인해 REST API키를 쓰고, 앱에서 웹뷰를 써서, 모달창으로 웹을 띄워서 로그인을 진행하는 걸로 결정했다.
따라서 REST API키를 복사해갔다.
소셜로그인을 위한 RN에서의 웹뷰 구현은 다른 게시글에 정리해두었으니 참고하면 될듯하고, 해당 게시글에서는 flask를 써서 어떻게 소셜로그인을 구현했는지 정리하고자 한다.
해당 방법은 PC 웹에서 소셜로그인 구현하고자 할때도 재활용할 수 있는 방식이다.
Flask에서 소셜로그인 구현하기
서론이 너무 길었다...이제 등장하는 주인공 flask...
우선 구현하면서 느낀게 express 보다 훨씬 간편하다. express에서는 소셜서비스와 통신하기 위해 server에서 axios를 import해야 했는데 flask에서는 그럴필요가 없어서 너무 간편했다.
1. 우선 client에서 서버 주소로 페이지 이동해준다.
-> 웹의 경우는 기존 깃헙 소셜로그인과 방식이 동일하고, RN을 쓸 경우, 웹뷰를 띄워야 하므로 약간 방법이 다르다.
2. 서버 주소로 페이지 이동 후, 서버에서 카카오 소셜서비스로 get 요청을 보낸다.
app/__init__.py
-> 해당 파일에서 path 경로 지정
1
2
3
|
from .main.controller.oauth import api as oauth
api.add_namespace(oauth, path="/oauth/kakao")
|
cs |
app/main/controller/oauth.py
-> 해당 파일에서 소셜서비스와의 통신 진행
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
from flask import request, redirect, jsonify, make_response
from flask_restx import Resource
from ..util.dto import UserDto
import requests
from ..service.oauth import social_signin
from ..config import kakao_client_id
api = UserDto.api
@api.route("/") # 카카오 로그인하기를 누르면 우선 해당 api로 오게되고, redirect를 통해 바로 request token을 받기 위해 링크가 변경됩니다.
class KakaoSignIn(Resource):
def get(self):
client_id = kakao_client_id
redirect_uri = "주소/oauth/kakao/callback"
kakao_oauthurl = f"https://kauth.kakao.com/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code"
return redirect(kakao_oauthurl)
|
cs |
3. 그러면 callback 주소로 request token이 전달되고, 이를 통해 소셜 서비스에 access token 요청 / access token으로 유저데이터 요청
을 진행한다.
app/main/controller/oauth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@api.route("/callback") # 위의 라우팅에서 redirect 되면서 바로 이 api로 오게됩니다.
class KakaoSignInCallback(Resource):
def get(self):
try:
code = request.args.get("code") # callback 뒤에 붙어오는 request token을 뽑아내 줍니다.
client_id = kakao_client_id
redirect_uri = "주소/oauth/kakao/callback"
#Python에서 HTTP 요청을 보내는 모듈인 requests
token_request = requests.get(
f"https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id={client_id}&redirect_uri={redirect_uri}&code={code}"
)
token_json = token_request.json() # 위의 get 요청을 통해 받아온 데이터를 json화 해주면 이곳에 access token 이 숨어있습니다.
error = token_json.get("error",None)
if error is not None :
return make_response({"message": "INVALID_CODE"}, 400) #에러 처리 한번 해주고
access_token = token_json.get("access_token") #카카오 소셜로그인을 통해 유저에 대한 정보를 받을 권한이 있는 토큰이 이것입니다.
# 여기까지가 access token 받아오는 통신
# 그리고 아래 코드가 access tokent 기반으로 유저 정보 요청하는 통신
profile_request = requests.get(
"https://kapi.kakao.com/v2/user/me", headers={"Authorization" : f"Bearer {access_token}"},
)
data = profile_request.json()
except KeyError:
return make_response({"message" : "INVALID_TOKEN"}, 400)
except access_token.DoesNotExist:
return make_response({"message" : "INVALID_TOKEN"}, 400)
return social_signin(data=data)
|
cs |
-> 파이썬에서는 " " 해당 따옴표 즉 문자열 내에서 변수를 주고자 하면 문자열을 뜻하는 따옴표 앞에 f 를 추가하고, 문자열 내에 변수들을 {} 해당 괄호로 감싸주면 된다.
4. 그럼 이제 service 폴더에서 유저 데이터를 DB에 저장하고 JWT로 토큰을 생성하는 과정을 진행한다.
social_signin은 service폴더에서 oauth의 DB 통신을 담당하는 함수를 import 해온 것이다.
app/main/service/oauth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
from flask import request, redirect
import jwt
from app.main import db
from app.main.model.users import Users
from ..config import jwt_key, jwt_alg
def social_signin(data):
kakao_account = data.get("properties")
email = kakao_account.get("nickname", None)
kakao_id = str(data.get("id")) # 모델에서 비번을 str으로 설정했기 때문에 여기서 문자열로 변경안해주면 에러가!
user = Users.query.filter_by(email=email).first() # 이메일값으로 쿼리 필터를 한번 해주고
if not user:
new_user = Users(
email=email,
password=kakao_id,
full_name=email,
mobile='null',
login='social'
)
save_social(new_user)
token = jwt.encode({"id":new_user.id}, jwt_key, jwt_alg)
token = token.decode("utf-8")
response_object = {
'status': 'success',
'message': 'you become a member for our service',
'Authorization': token
}
return response_object, 200
else:
user_id = user.id
print("user:", user_id)
token = jwt.encode({"id":user_id}, jwt_key, jwt_alg)
token = token.decode("utf-8")
response_object = {
'status': 'already signin',
'message': 'you already our member. login success',
'Authorization': token
}
return response_object, 201
def save_social(data):
db.session.add(data)
db.session.commit()
|
cs |
그럼 소셜로그인 끝! 여기서 만약에 일반적인 PC 웹이면, redirect를 통해 client 화면으로 변경되면서, 쿼리파라미터로 토큰을 보내줘야 한다. 그러나 우리는 RN으로 앱 제작 중이므로 client에서 데이터를 전달하는 방식이 조금 다르다!
서버는 위의 코드로써 소셜로그인 역할이 끝!
RN에서 소셜로그인 구현을 위한 코드는 다른 게시글에 정리해두었으니 참고!
'SW Engineering > BE' 카테고리의 다른 글
sequelize에서 foreign key 설정하기 (0) | 2021.01.12 |
---|---|
sequelize로 DB셋팅할 때, 환경변수 파일 설정 및 사용하기 (0) | 2021.01.12 |
소셜로그인 구현하기(Express.js / github social login) (0) | 2020.11.27 |
Flask 서버_flask-migrate (0) | 2020.11.20 |
Flask 서버구축하기_DB 설정하기(feat.Mysql/SQLAlchemy) (0) | 2020.11.20 |