장고로 카카오 소셜 로그인을 구현하는 과정과 고민 .
소셜 로그인을 구현하기 앞서 작동 방식을 이해하는 데 오랜시간을 사용했다. 다양한 블로그 글과 카카오 공식 홈페이지를 참고했다.
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api
그리고 로그인과 회원가입 로직을 노트에 적어서 흐름을 정리했다.

사실 처음부터 노트에 적지 않고 무작정 하나하나 치면서 만들다보니 자꾸꼬이고 헷갈려서 한번 노트에 흐름을 정리하고 만드니까 꼬이는 문제는 없어졌다.
처음부터 난관에 빠졌다.
카카오 로그인 페이지를 띄워야하는데 잠시 뇌정지가 와서 어떻게 백엔드단에서 띄우지 한참을 생각하다가 클라이언트에서 링크를 누르게 했다.

그리고 redirect_uri로 설정한 링크에 로그인 함수를 실행시켜서 하려했으나
깔끔하지 못함을 느끼고 수정했다.
<a href='{% url "kakaocode" %}'>
카카오 로그인
</a>
우선 카카오 로그인을 누르면 kakaocode url로 이동한다.
def kakao_code(request):
return redirect(f'https://kauth.kakao.com/oauth/authorize?client_id=f69e56958014d271373defb6cd2bbdc7&redirect_uri=http://127.0.0.1:8000/accounts/kakaologin/&response_type=code')
kakaocode함수가 실행되고 카카오 로그인 페이지로 이동시켰다.
그냥 리턴에 url을 적으면 그 페이지로 이동하는데 이걸 몰라서 애먹었다.
이제 유저가 카카오로그인을하고 나의 서비스에 동의를 하면 내가 설정한 redirect_uri에 인가코드(AUTHORIZATION_CODE)가 uri에 담긴다.
이제 인가코드를 사용해 토큰을 받고 유저 정보를 요청해보자
def kakao_signup(request):
AUTHORIZATION_CODE = request.GET.get('code',None)
REDIRECT_URI = "http://127.0.0.1:8000/accounts/kakaologin/"
kakao_token_api = "https://kauth.kakao.com/oauth/token"
data = {
'grant_type' : 'authorization_code',
'client_id' : REST_API_KEY,
'redirect_uri' : REDIRECT_URI,
'code' : AUTHORIZATION_CODE,
}
token_request = requests.post(kakao_token_api, data=data)
access_token = token_request.json()['access_token']
kakao_user_info = requests.post("https://kapi.kakao.com/v2/user/me", headers={"Authorization" : f"Bearer {access_token}"},).json()
kakaoid = kakao_user_info.get('id',None)
kakaoid = int(kakaoid)
kakaoaccounts = kakao_user_info.get('kakao_account')
AUTHORIZATION_CODE를 사용해서 토큰을 받아주었다.
토큰을 사용해서 사용자의 정보를 얻어왔다.
토큰으로 받아온 유저정보를 저정하려고 하는데 큰 고민이 생겼다.
카카오 계정 테이블을 새로 만들까?
아니면 기존 계정 테이블에 담을까?
기존의 계정 테이블에는 비밀번호 항목이 있으니 카카오 계정을 따로 만들었다.
def index(request):
message={}
if 'user' in request.session:
message['id'] = request.session['user']
return render(request, 'accounts/index.html', message)
기존에 인덱스 페이지에서 세션에 'user'를 키로 로그인 상태를 인식하게 했는데
문제는 새로운 카카오유저키 'kakaouser'도 같이 사용하니 로그인 인식이 중복으로 되는 문제가 생겼다.
def index(request):
message={}
if 'user' in request.session:
message['id'] = request.session['user']
return render(request, 'accounts/index.html', message)
if 'kakaouser' in request.session:
message['id'] = request.session['user']
return render(request, 'accounts/index.html', message)
그런데 지금 정리를 하면서 생각해보니 애시당초 카카오 로그인을 하면 카카오 계정에 저장하고 세션키는 'user'로 동일하게 사용하면 되는거였는데 계정 테이블이 2개라고 키를 2개 써서 만든 나의 실수 였다.
위에 설명한 문제 때문에 나는 카카오 계정 테이블을 지우고 기존 계정 테이블에 카카오계정도 집어넣으려고 했다.
class Accounts(models.Model):
user_id = models.CharField(
max_length=128,
unique=True,
)
email = models.EmailField(
max_length=128,
null=True,
)
password = models.CharField(
max_length=2048,
)
created = models.DateTimeField(
auto_now_add=True
)
나의 서비스는 이메일이 선택동의 이므로 이메일 정보를 못받아 올 수 있어서 이메일 필드에 null=True를 지정했다.
필수동의는 카카오에 서비스심사를 받아야해서 그렇게 됐다.
포스팅을 적으면서 느낀 건 그래서 소셜계정 데이터외 기존 계정테이블은 합치는게 좋은지 아닌게 좋은지 고민이 들었다.
지금까지 나의 소박한 로그인 기능을 만드는데에는 합치든 안 합치든 별 문제가 없어 보여서 궁금증이 생겼다.
그래서 인프런에 나는 구글로만 가입되어있는 상태인데 다른 소셜 계정으로 회원가입을 시도해봤다.
깃허브,카톡으로 가입하려고 하면 기존계정으로 바뀌고 애플로 회원가입은 됐다.
깃허브로 가입된 메일주소랑 카톡 메일주소는 다른데 어떻게 똑같이 인식을 하는지 모르겠다.
이 부분은 좀더 생각해봐야 할 것 같다.
if Accounts.objects.filter(user_id=kakaoid).exists():
user = Accounts.objects.get(user_id=kakaoid)
request.session['user'] = user.user_id
return redirect('index')
else:
kakao_accounts = Accounts(
user_id= kakaoid,
email = kakaoaccounts.get('email',None),
password = make_password(str(kakaoid)),
)
kakao_accounts.save()
user = Accounts.objects.get(user_id=kakaoid)
request.session['user'] = user.user_id
return redirect('index')
카톡에서 요청한 아이디가 계정 디비에 있으면 세션을 담아서 로그인 처리
아니면 계정을 생성하게했다.
이래서 유저는 카카오 로그인을 하나 로그인 회원가입을 하나 내부에서는 한개의 view만 작동해서 따로 로그인 회원가입 뷰를 나눌 필요가 없었다.
다만 기존 계정에 넣어야했기 때문에 비밀번호를 내가 makepassword함수를 사용해서 저장시키게 했다.
그래서 카카오 아이디 고유값을 비밀번호로 입력하면 로그인이 되는 상태가 됐다.
정리해보자면 결국 계정 디비의 생성에 대해서 크게 고민을 하지 않은게 문제점으로 계속 들어난다.
소셜계정을 기존 테이블에 관리를 할지 나눌지 에 대한 고민이 부족했고
합쳤다면 칼럼에 대한 고민을 하지 않았다.
비밀번호를 아이디로 생성하는것도 이상하고 여러모로 서비스를 한다고 생각하면 문제점이 많다.
노트에 구현하려는 로직의 흐름을 정리한게 코드를 짜기 쉽게 했다. 앞으로 기능을 구현하기전에 생각하고 노트에 정리하는 방법을 사용해야겠다고 느꼈다.