Skip to content

블로그 이사갔어요! https://milooy.github.io/

Fork my brain because I'm ready to commit

  • 블로그 이사갔어요! https://milooy.github.io/
  • Works
  • Activity
  • Programming
    • Programming 글목록 모음
    • Javascript
    • 일일코딩
    • Python
    • git
    • Front-End Programming
    • Programming notes
    • google analytics
  • Video
    • Music
    • etc
  • Artworks
  • Review
    • 덕력을 쌓자
    • Book
    • Movie
    • Things
    • 냠냠
  • 의미있는 주절거림
    • 일상
    • 영향을 받는다
    • poet
  • 넓어지기
    • 유용
    • 듣고보고정리하고
  • Uncategorized
Yurim Jin

Yurim Jin

아름다운 웹과 디자인, 장고와 리액트, 그리고 음악과 맥주를 사랑하는 망고장스터

View Full Profile →

인기쟁이 글

  • 블로그 이사갔어요! https://milooy.github.io/
  • 초심자를 위한 Github 협업 튜토리얼 (with 토끼와 거북이)
  • safari(혹은 webkit브라우저)에서 CSS Transition이 깜빡이며 잘 나오지 않을 때
  • 지하철 타고 서울 나들하기 좋은 곳 26곳
  • git rebase후 push 에러 해결
  • [Git] Pull Request를 보내기 전에, Rebase를 해야 할까요 혹은 merge commit을 만들어야 할까요?

Recent Posts

  • Apache Zeppelin 설치 및 빌드하기
  • GitHub Actions로 Vuepress 배포하기
  • npx create-react-app 에서 A template was not provided. This is likely because you’re using an outdated version of create-react-app. 에러가 날 때
  • Works
  • TIL(Today I Learned) – Personal wiki page

Social

  • View jay.jin.0427’s profile on Facebook
  • View jayjinjay’s profile on Twitter
  • View jyoolim1004@naver.com’s profile on LinkedIn
  • View milooy’s profile on GitHub

  • 9XD
  • 9X년생 개발자 모임
  • angularjs
  • book
  • C-School
  • codewars
  • conference
  • CSS
  • Data Analystic
  • database
  • django
  • event
  • FAIL
  • frontend
  • Galaxy3
  • galaxy S3
  • GIT
  • github
  • google analytics
  • google tag manager
  • hand
  • Head First
  • HTML
  • HTML5
  • http
  • Illustrator
  • Ipad
  • J
  • javascript
  • jQuery
  • logo
  • mac
  • markdown
  • markup
  • mdn
  • mySQL
  • npm
  • osx
  • pow
  • programmer
  • programming
  • prototype
  • python
  • react
  • rebase
  • social login
  • sublime text
  • template
  • UX
  • UX 디자인
  • UX디자인
  • works
  • youtube
  • zepl
  • 게임 프로그래밍
  • 그림
  • 기획
  • 디자인
  • 디자인리서치
  • 디지털노마드
  • 로고
  • 배색
  • 북리뷰
  • 빅게임
  • 삽질냠냠
  • 소설
  • 아이패드
  • 일러스트
  • 일러스트레이터
  • 일일코딩
  • 작당
  • 치앙마이
  • 특강
  • 페인터
  • 프로그래밍

Archives

  • November 2020
  • July 2020
  • December 2019
  • November 2019
  • September 2019
  • August 2019
  • June 2019
  • May 2019
  • January 2019
  • December 2018
  • October 2018
  • February 2018
  • January 2018
  • November 2017
  • September 2017
  • June 2017
  • May 2017
  • March 2017
  • November 2016
  • September 2016
  • July 2016
  • June 2016
  • May 2016
  • April 2016
  • March 2016
  • February 2016
  • January 2016
  • December 2015
  • November 2015
  • October 2015
  • September 2015
  • August 2015
  • July 2015
  • June 2015
  • May 2015
  • April 2015
  • March 2015
  • February 2015
  • September 2014
  • June 2014
  • May 2014
  • April 2014
  • March 2014
  • February 2014
  • December 2013
  • November 2013
  • October 2013
  • September 2013
  • August 2013
  • July 2013
  • June 2013
  • May 2013
  • April 2013
  • March 2013
  • February 2013
  • January 2013
  • December 2012

Tag: social login

[django] social auth 프로필 추가 페이지 달기 (feat. python-social-auth)

이 글은 [Django] oAuth2 소셜 로그인 기능 달기에서 이어집니다.

Problem

django-social-auth를 사용하여 핑크퐁 북스토어에 페이스북 로그인을 달았다.
우리는 추가 정보로 핸드폰 번호, SMS 수신 동의, email 수신 동의를 따로 받는데, 페이스북 가입 시에도 이를 처리할 페이지가 필요하다.

Solution

  1. optional_user_data: 유저 데이터를 받을 템플릿 연결
  2. save_profile: 위의 템플릿에서 받은 데이터를 프로필에 저장

두 개의 custom pipeline을 만든다. 사실 1과 2를 합치고 싶은데, 예제를 참고해 하다보니 두 함수로 나뉘게 되었다. 장알못의 슬픔…

settings.py

SOCIAL_AUTH_PIPELINE = (
    'social.pipeline.social_auth.social_details',
    'social.pipeline.social_auth.social_uid',
    'social.pipeline.social_auth.auth_allowed',
    'social.pipeline.social_auth.social_user',
    'social.pipeline.user.get_username', 

    'accounts.social.optional_user_data', # 얘 추가!

    'social.pipeline.user.create_user', # 중간에 create_user가 끼어있다

    'accounts.social.save_profile', # 얘 추가!

    'social.pipeline.social_auth.associate_user',
    'social.pipeline.social_auth.load_extra_data',
    'social.pipeline.user.user_details'
)

optional_user_data, save_profile을 파이프라인에 추가한다.
optional_user_data는 @partial이기 때문에 create_user위에 두어야 한다.
이는 공식 예제를 참고하였다.

save_profile 공식 예제: 링크

social.py

# -*- coding: utf-8 -*-
from functools import wraps

from django.shortcuts import render_to_response


def partial(func):
    @wraps(func)
    def wrapper(strategy, pipeline_index, *args, **kwargs):
        out = func(strategy=strategy, pipeline_index=pipeline_index,
                    *args, **kwargs) or {}
        if not isinstance(out, dict):
            values = strategy.partial_to_session(pipeline_index, *args,
                                                 **kwargs)
            strategy.session_set('partial_pipeline', values)
        return out
    return wrapper


@partial
def optional_user_data(backend, details, response, request, user, is_new=False, *args, **kwargs):
    if backend.name == 'facebook' and is_new:
        data = backend.strategy.request_data()
        if data.get('phone') is None:
            return render_to_response('registration/signup_option.html', {'fb_details': details, })
        else:
            return {'phone': data.get('phone')}


def save_profile(backend, user, response, is_new, *args, **kwargs):
    if backend.name == 'facebook' and is_new:
        data = backend.strategy.request_data()

        profile = user.profile
        profile.phone = data.get('phone', '')
        profile.email = response.get('email', '')
        profile.name = response.get('name', '')
        profile.sms_receiving_consent = data.get('sms_receiving_consent', '')
        profile.email_receiving_consent = data.get('email_receiving_consent', '')
        profile.save()

optional_user_data
backend가 facebook이고, 새로운 유저라면(로그인/가입 동시에 처리하기 때문에 is_new면 첫 가입 상태로 판별하면 된다) signup_option.html템플릿을 보여준다.
data에 backend.strategy.request_data()를 저장한다. 이는 form에서 보낸 데이터들이 저장된다. 맨 처음 접근하면 phone 데이터가 없으니 if data.get('phone') is None:로 들어간다.
signup_option.html의 form에서 post로 데이터를 보내면 else타고 나간다.

맨 앞에 @partial도 붙여야 한다. 내 경우는 왠지 모르게 from social.pipeline.partial import partial이 계속 에러나서 그냥 @partial함수 자체를 가져왔다. (삽질삽질)

save_profile
optional_user_data에서 저장한 form data를 data변수에 저장한다.
심호흡을 한 뒤 response나 data에서 원하는 데이터들을 받아와 user.profile에 저장한다.
data.get('sms_receiving_consent', '')에서 뒤에 ”를 넣지 않으면 null인 경우에 아무것도 저장이 안나서 에러가 날 수 있다.

signup_option.html

{% block content %}
    <h4 class="header">선택정보 입력</h4>
    안녕하세요, {{ fb_details.username }}님!
    <form id="signup_form" method="post" action="/social/complete/facebook/">
        {% csrf_token %}
        <input type="hidden" name="next" value="{{ next }}"/>

        <div class="row">
            <h5 class="header col s12">선택 정보</h5>
            <div class="input-field col s12">

                휴대폰 번호
            </div>
            <div class="col s12">
                <div class="">
                    <div class="checkbox">
                         이메일 수신 동의
                    </div>
                </div>
            </div>
            <div class="col s12">
                <div class="">
                    <div class="checkbox">
                         SMS 수신 동의
                    </div>
                </div>
            </div>
        </div>
        <div class="action">

                <i class="material-icons">send</i>
                가입하기

        </div>
    </form>
{% endblock %}

action을 action="/social/complete/facebook/"처럼 적어준다. 나는 python-social-auth는 url 앞에 /social/을 달아줬기 때문에 그것도 붙였다.

Conclusion

점점 장(고)알(지도)못(하는사람)에서 장덜알못이 되어가고 있다.
장고덕에 차근차근 혼자 기능을 만들어가고 있다. 고맙고 미운 장고.

Posted on February 23, 2016February 23, 2016Categories PythonTags django, python, python-social-auth, social loginLeave a comment on [django] social auth 프로필 추가 페이지 달기 (feat. python-social-auth)

[Django] oAuth2 소셜 로그인 기능 달기(feat. python-social-auth)

Django에서 이러한 Social Login을 이용하기 위한 라이브러리는 여러개가 있었고, 대표적으로는 django-social-auth와 python-social-auth가 있었지만, 두 프로젝트 모두 현재(2017.02.08기준) Deprecated되었고 이 프로젝트들은 python-social-auth가 org자체로 이전해 social-auth-app-django로 바뀌었습니다.

장고 페이스북 가입 달기

장고로 만든 개인 사이트에 소셜 가입 기능을 붙이려 한다.
python-social-auth를 써서 만들어본다.
나는 email을 기본 아이디로 쓰도록 User Model을 확장해두었는데, 그것때문에 많이 삽질했다. 징글징글~~~ 세륜장고… 사라져주세요… 아 아니 사라지진 말아요.

oAuth

일단 oAuth에 대해 간단히 알고 시작한다. 네이버 D2 블로그

python-social-auth 설치하기

공식 독스를 참고하여 설치한다.
참고: KwangYoun Jung님 블로그

pip install python-social-auth

핍으로 설치해주고, 센스있게 requirements.txt에도 써준다. Installed_apps에도 써준다.

INSTALLED_APPS = [
    ...
    'social.apps.django_app.default',
    ...
]

환경설정

settings.py에 필요한 환경설정을 해준다.
페이스북 디벨로퍼 사이트에 들어가서 클릭클릭 해서 앱을 만들어준다. 별로 어렵지 않다. 거기서 얻은 키, 시크릿키를 넣어준다.

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.core.context_processors.debug',
    'django.core.context_processors.i18n',
    'django.core.context_processors.media',
    'django.core.context_processors.static',
    'django.core.context_processors.tz',
    'django.contrib.messages.context_processors.messages',
    'social.apps.django_app.context_processors.backends',
    'social.apps.django_app.context_processors.login_redirect',
)

AUTHENTICATION_BACKENDS = (
    'social.backends.facebook.FacebookOAuth2',
    # 'social.backends.google.GoogleOAuth2',
    # 'social.backends.twitter.TwitterOAuth',
    'django.contrib.auth.backends.ModelBackend',
)

SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/'
SOCIAL_AUTH_URL_NAMESPACE = 'social'

# Facebook
SOCIAL_AUTH_FACEBOOK_KEY = '페북에서 받아온 키를 넣으세요'
SOCIAL_AUTH_FACEBOOK_SECRET = '페북에서 받아온 시크릿키를 넣으세요'

# Google
# SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = ''
# SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = ''

# Twitter
# SOCIAL_AUTH_TWITTER_KEY = ''
# SOCIAL_AUTH_TWITTER_SECRET = ''

SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'

SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']
# FACEBOOK_EXTENDED_PERMISSIONS = ['email', 'picture']
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
  'fields': 'id, name, email, age_range'
}

이메일은 디폴트로 받아오지 않으므로, 이메일을 쓰고 싶다면 하단의 변수들을 추가해준다.
변수명은 페이스북 사이트를 참고한다.

(+추가)
FACEBOOK_EXTENDED_PERMISSIONS에 email을 추가해주니, 이게 기본 email을 덮어씌워서 페이스북에서 ‘추가 이메일’이 입력된 것을 받아오게 되어버렸다. 그래서 추가 이메일을 쓰지 않은 사람은 이메일을 받아오지 못하는 불상사가… 부들부들… 이틀 헤맸다.

urls.py

urls.py에도 추가해준다.

url(r'', include('social.apps.django_app.urls', namespace='social')),

base.html

페북 앱을 만들면 생기는 스크립트를 여는 바디태그 뒤에 넣어준다.

<br />

html엔 이런 식으로 추가해주면 기본적인 동작은 한다.
기본 유저모델로 끝나면 좋겠지만, 만약 가입에 다른 절차들이 필요하다면 몇 가지 작업이 필요하다.

  1. 이메일을 기본 아이디로 쓰고
  2. 닉네임을 필수로 만들고
  3. 프로필 사진을 받음

내 유저모델은 가입시 이런 절차가 필요한데, 페이스북하고 연동할 때에 이를 ‘어답터’처럼 연결할 함수가 필요하다.

Pipeline

python-social-auth에선 파이프라인이란 개념으로 이를 해결한다.
회원가입이 진행되는 동안 수행되는 일련의 함수가 있는데, 이 함수 사이에 필요한 기능이 들어간 함수를 집어넣거나, 기존에 만들어진 함수를 덮어쓰는 식으로 제어한다.
공식사이트의 설명을 참고.

settings.py

SOCIAL_AUTH_PIPELINE = (
    'social.pipeline.social_auth.social_details',
    'social.pipeline.social_auth.social_uid',
    'social.pipeline.social_auth.auth_allowed',
    'social.pipeline.social_auth.social_user',
    'social.pipeline.user.get_username',
    # 'social.pipeline.user.create_user',
    'accounts.social.create_user', # 덮어씀
    'accounts.social.update_avatar', # 추가함
    'social.pipeline.social_auth.associate_user',
    'social.pipeline.social_auth.load_extra_data',
    'social.pipeline.user.user_details'
)

settings.py에 파이프라인 플로우를 적어준다.
accounts앱에 social.py를 만들어서, create_user함수는 덮어쓰고, update_avatar함수를 새로 만들어주었다.

social.py

from urllib.request import urlopen

from django.core.files.base import ContentFile
from social.utils import slugify

USER_FIELDS = ['email', 'nickname']

def create_user(strategy, details, user=None, *args, **kwargs):
    print(details)
    print(kwargs)
    if user:
        return {'is_new': False}

    fields = {'email': details.get('email'), 'nickname': details.get('username')}

    if not fields:
        return

    return {
        'is_new': True,
        'user': strategy.create_user(**fields)
    }

def update_avatar(backend, response, uid, user, *args, **kwargs):
    if backend.name == 'facebook':
        url = &amp;quot;http://graph.facebook.com/%s/picture?type=large&amp;quot; % response['id']
        avatar = urlopen(url)
        user.avatar.save(slugify(user.email + &amp;quot; social&amp;quot;) + '.jpg', ContentFile(avatar.read()))
        user.save()

create_user함수에서, 원래는 USER_FIELDS가 들어가던 것을, email과 nickname이 들어가도록 교체해줬다.
update_avarter는 create_user다음에 불리는 함수인데, 페이스북 아바타를 저장하고 user model에 넣어주는 기능을 한다.

끝~

스크린샷 2016-02-19 오후 7.14.40
끝났다. 모쪼록 less 삽질에 도움이 되었으면 좋겠습니다.

Refer

http://initialkommit.github.io/2015/04/27/django-newbie-adding-facebook-authentication-to-a-django-app/

http://codingdojang.com/scode/280
https://github.com/omab/django-social-auth
http://django-social-auth.readthedocs.org/en/latest/installing.html

http://javaguirre.net/2013/11/06/creating-a-user-profile-in-python-social-auth-in-django/
http://i5on9i.blogspot.kr/2016/01/django-social-log-in-library.html

Posted on February 19, 2016September 6, 2017Categories Python, UncategorizedTags django, programming, python, social login4 Comments on [Django] oAuth2 소셜 로그인 기능 달기(feat. python-social-auth)
  • Follow Following
    • 블로그 이사갔어요! https://milooy.github.io/
    • Join 81 other followers
    • Already have a WordPress.com account? Log in now.
    • 블로그 이사갔어요! https://milooy.github.io/
    • Customize
    • Follow Following
    • Sign up
    • Log in
    • Report this content
    • View site in Reader
    • Manage subscriptions
    • Collapse this bar
 

Loading Comments...