바뀜

5,880 바이트 추가됨 ,  2022년 12월 2일 (금) 05:43
1번째 줄: 1번째 줄:     
==개요==
 
==개요==
유명하지 않은 사이트의 계정을 다 기억하는 건 참 어려운 일. 이럴 땐 공신력을 갖춘 외부 서비스의 인증기능에 위임하여 사용하면 편하다.
+
sns 로그인. 유명하지 않은 사이트의 계정을 다 기억하는 건 참 어려운 일. 이럴 땐 공신력을 갖춘 외부 서비스의 인증기능에 위임하여 사용하면 편하다.
<br />
+
 
 +
=== 사용 ===
 +
기본적으로 username 필드에 정보를 담아준다. 자동으로 user1, user2, user3... 순으로 생성해준다. 장고에서 사용하는 AUTH 모델의 객체를 지우면 소셜계정 정보도 함께 지워진다.
 +
 
 +
각 sns에서 제공하는 이름, 생년월일 따위의 정보는 어떻게 받는지 모르겠다 ㅜㅜ
 +
 
 +
=== 들어가기 전에 ===
 +
 
 +
* 커스텀 유저 모델을 작성하자.
 +
*:- 소셜 로그인을 구현한 후 [[회원관리 2. 커스텀유저(AbstractUser 이용)|커스텀 유저 만들기]]를 진행하는 중 DB를 지우고 말았다. 결국 작업을 다시 수행해야 해서 불편하다.
 +
*:- 이후 조금이라도 커스텀 유저모델을 사용할 기미가 보인다면 이를 미리 만들어 둔 후에 소셜 로그인을 구현하는 편이 좋다.
 +
*:- 커스텀 모델 작성 시 username 필드를 만들어두어야 한다.(sns login에서 사용하는 필드)
    
==사전작업==
 
==사전작업==
8번째 줄: 19번째 줄:     
===settings.py 설정===
 
===settings.py 설정===
<code>INSTALLED_APPS = [</code>하위에 다음과 같은 내용들을 추가해 넣어준다.<syntaxhighlight lang="python">
+
{| class="wikitable"
 +
!과정
 +
!설명
 +
!코드
 +
|-
 +
| rowspan="2" |<code>INSTALLED_APPS</code>
 +
|<code>INSTALLED_APPS</code> 하위에 우측 앱들을 추가한다.
 +
|<syntaxhighlight lang="python">
 
'django.contrib.sites',  # 사이트 정보를 설정하기 위해 필요
 
'django.contrib.sites',  # 사이트 정보를 설정하기 위해 필요
 
# allauth 관련 앱 목록 추가
 
# allauth 관련 앱 목록 추가
14번째 줄: 32번째 줄:  
'allauth.account',  # 가입한 계정을 관리하기 위한 것.
 
'allauth.account',  # 가입한 계정을 관리하기 위한 것.
 
'allauth.socialaccount',  # 소셜 계정을 관리하기 위한 것.
 
'allauth.socialaccount',  # 소셜 계정을 관리하기 위한 것.
 +
</syntaxhighlight>
 +
|-
 +
|<code>INSTALLED_APPS</code> 하위에 서비스 해준 sns 계정을 추가한다.
 +
사용 가능한 공급자는 다음 [https://django-allauth.readthedocs.io/en/latest/providers.html 링크]에서 확인하자.
 +
|<syntaxhighlight lang="python">
 
# 사용할 외부기능을 추가한다.
 
# 사용할 외부기능을 추가한다.
 
'allauth.socialaccount.providers.naver',
 
'allauth.socialaccount.providers.naver',
 
'allauth.socialaccount.providers.google',
 
'allauth.socialaccount.providers.google',
 
+
</syntaxhighlight>
#이미 있다면, 하위에 추가.
+
|-
 +
|AUTHENTICATION_BACKENDS
 +
|AUTHENTICATION_BACKENDS 하위에 추가한다.
 +
(일반적으로 없어, 우측의 코드를 다 써주면 된다.)
 +
|<syntaxhighlight lang="python">
 +
# 이미 있다면, 하위에 추가.
 
AUTHENTICATION_BACKENDS = [
 
AUTHENTICATION_BACKENDS = [
 
     # Needed to login by username in Django admin, regardless of `allauth`
 
     # Needed to login by username in Django admin, regardless of `allauth`
25번째 줄: 53번째 줄:  
     'allauth.account.auth_backends.AuthenticationBackend',
 
     'allauth.account.auth_backends.AuthenticationBackend',
 
]
 
]
  −
#TEMPLATES의 하위의 context_processors 아래에 'django.template.context_processors.request',를 추가해넣는다.
  −
            'context_processors': [
  −
                'django.template.context_processors.request',
   
</syntaxhighlight>
 
</syntaxhighlight>
 
+
|-
 +
|context_processors
 +
|TEMPLATES의 하위의 context_processors 아래에 'django.template.context_processors.request',를 추가해넣는다.
 +
|<syntaxhighlight lang="python">
 +
'context_processors': [
 +
    'django.template.context_processors.request',
 +
    ...
 +
</syntaxhighlight>
 +
|}
 
===urls.py 설정===
 
===urls.py 설정===
 
다음과 같이 url을 추가해준다.<syntaxhighlight lang="python">
 
다음과 같이 url을 추가해준다.<syntaxhighlight lang="python">
 
urlpatterns = [
 
urlpatterns = [
 
     path('accounts/', include('allauth.urls')), # allauth의 기능을 accounts라는 주소 아래 담는다.
 
     path('accounts/', include('allauth.urls')), # allauth의 기능을 accounts라는 주소 아래 담는다.
</syntaxhighlight>여기까지 하고 DB에 반영을 해주면 admin에서 '소셜 계정'이라는 모델집단을 볼 수 있다.
+
</syntaxhighlight>여기까지 하고 DB에 반영을 해주면 admin에서 '소셜 계정'이라는 모델집단을 볼 수 있다.(<code>python manage.py makemigrations, python manage.py migrate</code>)
   −
python manage.py migrate
+
이후 admin에 접속해보자. 그러면 다음과 같은 에러를 만난다.
 
  −
그러면 다음과 같은 에러를 만난다.
      
django.contrib.sites.models.Site.DoesNotExist: Site matching query does not exist.
 
django.contrib.sites.models.Site.DoesNotExist: Site matching query does not exist.
   −
앱에 'django.contrib.sites'가 추가되었기 때문에 발생하는 에러인데, settings.py 아무데나 SITE_ID = 1을 지정해주면 된다. SITE_ID=1  # 무슨의미일까?
+
앱에 'django.contrib.sites'가 추가되었기 때문에 발생하는 에러인데, settings.py 아무데나 SITE_ID = 1을 지정해주면 된다.(운영하는 사이트 중 첫번째 사이트로 리다이렉트하게 한다.)<br />
<br />
      
===site 설정===
 
===site 설정===
54번째 줄: 83번째 줄:  
*서비스 url은 로컬환경에서 개발중이라면 http://localhost:포트번호 형식으로 등록한다.
 
*서비스 url은 로컬환경에서 개발중이라면 http://localhost:포트번호 형식으로 등록한다.
 
*callback URL은 [https://django-allauth.readthedocs.io/en/latest/providers.html#naver allauth 문서]에서 참고하면 된다.
 
*callback URL은 [https://django-allauth.readthedocs.io/en/latest/providers.html#naver allauth 문서]에서 참고하면 된다.
 +
*아래 과정을 진행하다가 소셜어플리케이션 객체를 작성하면 <code>FOREIGN KEY constraint failed</code> 에러를 만나기도 하는데... 이는 DB를 밀고 새로 <code>migrate</code>를 진행하면 문제 없이 진행된다.(역시... 회원관리 모델은 의존성 문제 때문에 에러가 많이 생기니, 프로젝트의 극초반에 진행해주어야 한다.)
    
{| class="wikitable"
 
{| class="wikitable"
62번째 줄: 92번째 줄:  
|네이버
 
|네이버
 
|
 
|
*[https://developers.naver.com/products/login/api/ 네이버아이디로 로그인] 서비스에서 오픈 API를 신청한다.
+
#[https://developers.naver.com/products/login/api/ 네이버아이디로 로그인] 서비스에서 오픈 API를 신청한다.
*callback url : http://http://127.0.0.1:8000/accounts/naver/login/callback/ 형태.
+
#callback url : http://http://127.0.0.1:8000/accounts/naver/login/callback/ 형태.
*소셜어플리케이션에서 얻은 클라이언트 아이디와 비밀키를 입력한다.
+
#소셜어플리케이션에서 얻은 클라이언트 아이디와 비밀키를 입력한다.
*등록할 때 이용가능한 사이트를 모두 선택해준다.(example.com 이라도 안해주면 에러가 난다.)
+
#등록할 때 이용가능한 사이트를 모두 선택해준다.(example.com 이라도 안해주면 에러가 난다.)
*로그인 버튼은 다음 [https://developers.naver.com/docs/login/bi/ 링크]에서 제공받을 수 있다.
+
#로그인 버튼은 다음 [https://developers.naver.com/docs/login/bi/ 링크]에서 제공받을 수 있다.
 +
개발자 외 일반사용자의 로그인은 네이버의 인증을 받아야 한다.(사이트개발이 완전히 끝난 후에 로그인 과정 제출.)
 
|-
 
|-
 
|구글
 
|구글
|[https://console.developers.google.com/projectselector2/apis/dashboard?supportedpurview=project 구글 API 콘솔]에서 진행한다.
+
|준비물
API를 사용하기 위해선 프로젝트가 있어야 한다. 프로젝트를 만들고..
     −
좌측 메뉴의 '사용자 인증 정보' 선택 > OAuth 클라이언트 ID를 만든다.
+
* 진행하기 전에 도메인에서 https:// 를 사용할 수 있어야 한다.
    +
# [https://console.developers.google.com/projectselector2/apis/dashboard?supportedpurview=project 구글 API 콘솔]에서 진행한다. API를 사용하기 위해선 프로젝트가 있어야 한다. 프로젝트를 만들고..
 +
# 좌측 메뉴의 '사용자 인증 정보' 선택 > OAuth 클라이언트 ID를 만든다.(웹어플리케이션으로.)
 +
# 리다이렉션 url은 https://localhost:8000/accounts/google/login/callback/ 형태.
 +
# 만들 때 ID와 비밀키를 주는데, 이들을 소셜어플리케이션에 등록한다.(비밀키는 처음에만 알려주고 곧 안나오게 될 수 있다. 지멋대로다 나왔다 안나왔다...)
 +
# 로그인 버튼은 다음 [https://developers.google.com/identity/branding-guidelines#sign-in-button 링크]에서.
 +
|-
 +
|카카오
 +
|
 +
# settings.py 의 INSTALLED_APPS 안에 'allauth.socialaccount.providers.kakao',를 추가한다.
 +
# API키를 신청한다.(https://developers.kakao.com/<nowiki/>에서)  - 신청할 때 리다이렉트 url로 http://127.0.0.1:8000/accounts/kakao/login/callback/ 형태.
 +
# admin의 소셜어플리케이션에서 클라이언트아이디에 REST API 키를 넣는다.(시크릿 키는 없다.)
 +
# 로그인버튼은 [https://developers.kakao.com/tool/resource/login 링크]에서 제공받을 수 있다.
 +
|-
 +
|페이스북
 +
|사용하기 위해 <nowiki>https://를</nowiki> 사용할 수 있어야 한다.
   −
API를 신청한다.
+
# settings.py 의 INSTALLED_APPS 안에 'allauth.socialaccount.providers.facebook', 추가
 +
# https://developers.facebook.com/apps/<nowiki/>에서 앱을 만든다.
 +
# 앱 메뉴의 '페이스북 로그인 설정'에서 유효한 OAuth 리다이렉션에 [http://127.0.0.1:8000/accounts/kakao/login/callback/ http://127.0.0.1:8000/accounts/facebook/login/callback/]형태로 기입한다.
 +
# <code>페이스북디벨로퍼>설정>기본설정</code>에서 앱ID와 비밀코드를 보여주는데, 이를 장고소셜로그인 앱에 등록한다.
 +
# 로그인 버튼은 [https://developers.facebook.com/docs/facebook-login/web/login-button?locale=ko_KR 링크]에서 자바스크립트와 함께 제공된다.(자바스크립트를 사용한 버튼은... 이것저것 꼬이게 하니, 이미지만 따오도록 하자.)
 
|-
 
|-
|
+
|애플
 
|
 
|
 
|}
 
|}
다른 곳에선... 사이트들에 서비스하는 사이트(http://127.0.0.1:8000/<nowiki/>)를 등록하는데... 일단 안하고 진행해볼까?
     −
<br />
+
==== 포기 ====
 +
{| class="wikitable"
 +
!서비스
 +
!설명
 +
|-
 +
|인스타그램
 +
|페이스북과 한 몸. 관련 앱 생성 후 리다이렉션 주소만 http://localhost:8000/accounts/instagram/login/callback/ 형태로 추가.
 +
그러나... 인스타 자체에서 로그인으로 사용할 수 없다고 못박아 두어서... 하다가 포기.(22.12월 기준 API 요청이 계속 거부당한다. 아마 최신화가 되지 않은듯...?)
 +
|}
    
==탬플릿 만들기==
 
==탬플릿 만들기==
107번째 줄: 163번째 줄:  
</div>
 
</div>
 
<ul class="socialaccount_providers">
 
<ul class="socialaccount_providers">
 
+
<!--  프로바이더의 순서는 settings.py에 지정한 순서인 듯하다.  -->
 
{% for provider in socialaccount_providers %}
 
{% for provider in socialaccount_providers %}
 
{% if provider.id == "openid" %}
 
{% if provider.id == "openid" %}
128번째 줄: 184번째 줄:  
                 onmouseleave="this.src='{{ naver_button }}'"height="34">
 
                 onmouseleave="this.src='{{ naver_button }}'"height="34">
 
     </div>
 
     </div>
 +
   
 +
<!-- 다양한 방식으로 구성할 수 있다. -->
 +
{% elif provider.name == "Kakao" %}
 +
<a href="{% provider_login_url 'kakao' method='oauth2' %}">
 +
카카오톡 회원가입
 +
</a>
 +
       
 
{% else %}
 
{% else %}
 
<li>
 
<li>
143번째 줄: 206번째 줄:     
관리자페이지의 소셜계정 앱 안의 소셜계정 모델이 추가되는 것과 동시에 기본 인증앱의 Users 모델에 새로운 모델이 추가되어 있다.
 
관리자페이지의 소셜계정 앱 안의 소셜계정 모델이 추가되는 것과 동시에 기본 인증앱의 Users 모델에 새로운 모델이 추가되어 있다.
 +
 +
<br />
 +
= 기타 기능 =
 +
user.socialaccount_set.all().first() 안에 해당 제공자로부터 받아오는 각종 정보들이 담긴다. dir로 확인해 사용해보자.
 +
 +
이외 기존 회원과 소셜계정의 연결도 가능한 듯한데... 이상하게 안된다. 결국 스스로 머릴 써서 우회해서 구현했다.
 +
 +
대충 다음과 같은 속성들이 있다.<syntaxhighlight lang="html">
 +
    get_avatar_url. {{account.get_avatar_url}}
 +
    제공자. {{ account.provider }}
 +
    get_deferred_fields. {{ account.get_deferred_fields }}
 +
    get_profile_url. {{ account.get_profile_url }}
 +
    get_provider_account. {{ account.get_provider_account }}  # 카카오, 네이버의 경우 닉네임을 받으면 여기에 담긴다.(아이디를 제공하는 경우는 거의 없다.)
 +
    get_provider_display. {{ account.get_provider_display }}
 +
    id. {{ account.id }}
 +
</syntaxhighlight>
 +
<references />
 +
 +
= 에러 =
 +
 +
=== DoesNotExist at /accounts/kakao/login/ ===
 +
 +
=== SocialApp matching query does not exist. ===
 +
위와 같은 에러가 뜨는 경우는 admin에 소셜어플리케이션을 등록할 때 site를 지정해주지 않으면 뜬다.
    
==기존 회원관리 뷰 수정==
 
==기존 회원관리 뷰 수정==
152번째 줄: 239번째 줄:     
login(request, user, backend='django.contrib.auth.backends.ModelBackend')
 
login(request, user, backend='django.contrib.auth.backends.ModelBackend')
  −
<br />
  −
<references />
   
[[분류:장고 기능구현(초급)]]
 
[[분류:장고 기능구현(초급)]]