Django RestFramework OAuth2 - Tirrilee/TechTalk GitHub Wiki

Django RestFramework OAuth2


Facebook ์—ฐ๋™ ๋ฐฉ๋ฒ•

INSTALLED_APPS = (
    ...
    # OAuth
    'oauth2_provider',
    'social_django',
    'rest_framework_social_oauth2',
)

REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        ...
        # OAuth
        # 'oauth2_provider.ext.rest_framework.OAuth2Authentication',  # django-oauth-toolkit < 1.0.0
        'oauth2_provider.contrib.rest_framework.OAuth2Authentication',  # django-oauth-toolkit >= 1.0.0
        'rest_framework_social_oauth2.authentication.SocialAuthentication',
    )
}

REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        ...
        # OAuth
        'oauth2_provider.contrib.rest_framework.OAuth2Authentication',  # django-oauth-toolkit >= 1.0.0
        'rest_framework_social_oauth2.authentication.SocialAuthentication',
    )
}

AUTHENTICATION_BACKENDS = (

    # Facebook OAuth2
    'social_core.backends.facebook.FacebookAppOAuth2',
    'social_core.backends.facebook.FacebookOAuth2',

    # django-rest-framework-social-oauth2
    'rest_framework_social_oauth2.backends.DjangoOAuth2',

    # Django
    'django.contrib.auth.backends.ModelBackend',
)

# Facebook configuration
SOCIAL_AUTH_FACEBOOK_KEY = '<your app id goes here>'
SOCIAL_AUTH_FACEBOOK_SECRET = '<your app secret goes here>'

# Define SOCIAL_AUTH_FACEBOOK_SCOPE to get extra permissions from facebook. 
# Email is not sent by default, to get it, you must request the email permission:
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
    'fields': 'id, name, email'
}

KakaoTalk ์—ฐ๋™ ๋ฐฉ๋ฒ•

AUTHENTICATION_BACKENDS = (
    # KAKAO OAuth2
    'social_core.backends.kakao.KakaoOAuth2',
)

# Kakao configuration
SOCIAL_AUTH_KAKAO_KEY = '<your kakao key goes here>'
SOCIAL_AUTH_KAKAO_SCOPE = ['email']

pipeline

SOCIAL_AUTH_PIPELINE = (
    # user์— ๋Œ€ํ•ด์„œ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์ •๋ณด์™€, ์ดํ›„์— user instance๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ„๋‹จํ•œ format
    'social_core.pipeline.social_auth.social_details',

    # ์šฐ๋ฆฌ๊ฐ€ ๊ถŒํ•œ์„ ์ค€ ์–ด๋–ค ์„œ๋น„์Šค๋กœ๋ถ€ํ„ฐ ์–ป์€ social uid
    'social_core.pipeline.social_auth.social_uid',

    # ํ˜„์žฌ auth process์˜ validation์„ ํ™•์ธ
    # email์ด๋‚˜ domain์ด whitelists์— ์ ์šฉ์ด ๋˜๋Š”์ง€ ๋“ฑ 
    'social_core.pipeline.social_auth.auth_allowed',

    # social-account๊ฐ€ ์ด๋ฏธ site์— ์†ํ•ด์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌ
    'social_core.pipeline.social_auth.social_user',

    # username์„ ๋งŒ๋“ค๊ณ  ๋งˆ์ง€๋ง‰์— random string์„ ๋ถ™์ž„ (์ถฉ๋Œ์ด ์žˆ์„ ๋•Œ)
    'social_core.pipeline.user.get_username',

    # email address๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด validation email์„ ๋ณด๋ƒ„
    # 'social_core.pipeline.mail.mail_validation',

    # ํ˜„์žฌ ํ• ๋‹น๋œ social detail์— ๋น„์Šทํ•œ ์ด๋ฉ”์ผ์„ ๊ฐ€์ง„ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋ฅผ ์ถ”๊ฐ€
    # 'social_core.pipeline.social_auth.associate_by_email',

    # ์‚ฌ์šฉ์ž๋ฅผ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค๋ฉด User ์ƒ์„ฑ
    'social_core.pipeline.user.create_user',

    # ์ค‘๊ฐ„์— Profile์„ ๋“ฑ๋กํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— 
    'profiles.pipeline.create_profile', # ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์„œ ๋“ฑ๋กํ•œ pipeline

    # social account์— ํ• ๋‹น๋œ record ์ƒ์„ฑ
    'social_core.pipeline.social_auth.associate_user',

    # social record ์—์„œ ํ• ๋‹น๋œ ๊ฐ’๊ณผ ํ•จ๊ป˜ extra_data field๋ฅผ ๋ง๋ถ™์ž„
    'social_core.pipeline.social_auth.load_extra_data',

    # auth service์—์„œ ๋ฐ”๋€ ๋ฐ์ดํ„ฐ ์ •๋ณด๋ฅผ ์—…๋ฐ์ดํŠธ
    'social_core.pipeline.user.user_details',
)

Custom Pipeline

from urllib.request import urlopen
from django.core.files.base import ContentFile
from django.contrib.auth.models import User
from profiles.models import Profile

def create_profile(backend, user, response, *args, **kwargs):
    profile = Profile(user=user) if kwargs['is_new'] else Profile.objects.get(user__username=user.username)
    if backend.name == 'facebook':
        profile.email = response.get('email', '')
    elif backend.name == 'kakao':
        properties = response.get('properties', '')
        if properties != '':
            profile.nick_name = properties.nickname
    else:
        return 0
    profile.save()

urls

urlpatterns = [
    path('auth/', include('rest_framework_social_oauth2.urls')),
] 

Application ๋“ฑ๋ก

django admin์˜ Application model ์— ์ƒˆ๋กœ์šด Application ํ•œ ๊ฐœ๋ฅผ ๋“ฑ๋กํ•œ๋‹ค.

  • Client ID : ์นด์นด์˜คํ†ก์—์„œ ์–ป์–ด์˜จ Key, Facebook์—์„œ ์–ป์–ด์˜จ APP ID
  • User ์„ ํƒ
  • Client Type : Public
  • Authorization Grant Type : Client credentials

Test

localhost:8000/auth/convert-token ์—์„œ POST ๋กœ

{
	"grant_type" : "convert_token",
	"client_id" :"kakaotalk client id",
	"backend":"kakao",
	"token":"access token"
}

๋ฅผ ๋ณด๋‚ด๋ฉด response๊ฐ€ ์˜จ๋‹ค.


๋ฐฐํฌ (elatic beanstalk)

.ebextensions ์ƒ์„ฑ

$ mkdir .ebextensions

$ vi django.config

option_settings:
  aws:elasticbeanstalk:container:python:
    WSGIPath: sinabro/wsgi.py # wsgi.py ํŒŒ์ผ์ด ์žˆ๋Š” ๊ฒฝ๋กœ

eb deploy

$ eb init

$ eb create

$ eb deploy


๋ฐฐํฌ์‹œ ์ฃผ์˜ํ•  ์ 

WSGIPassAuthorization๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ OFF ๋˜์–ด์žˆ๋Š”๋ฐ ์ด ๊ฐ’์„ ON ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผํ•œ๋‹ค.

๋งŒ์•ฝ OFF๋กœ ํ•ด๋†“์œผ๋ฉด 401 UnAuthorized / Invalid token header. No credentials provided ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

WSGIPassAuthorizaion ๋ฌธ์ œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

.ebextensions ์•„๋ž˜์— wsgi_custom.config (์ด๋ฆ„์€ ์ƒ๊ด€์—†์Œ) ์„ ๋งŒ๋“ค๊ณ 

files:
  "/etc/httpd/conf.d/wsgihacks.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      WSGIPassAuthorization On

ํ•ด๋‹น ๊ฐ’์„ ์ถ”๊ฐ€ํ•œ๋‹ค.


Request

GET Access Token

{
"grant_type" : "convert_token",
"client_id" :"",
"backend":"google-oauth2",
"token":"ya29.GlyCBha5vkQ_r2vok-dMeC1gyNFOVGpkgx_OA_-On1pw0โ€ฆn-YEQ3G8amzhonFw8kWiew4SOQ5HkLZWFF8mg2EjfeIimUiEg"
}
{
"grant_type" : "convert_token",
"client_id" :"",
"backend":"facebook",
"token":"EAAcp1dqQxVYBAHC4BV2FskQigFMlP4qv3nO2sFAOZAkS8X1nZBTd3XTcLQzoDDuAq9RKh9ZBKa79FZAekrz5TSHl49iI2eNF3L1qUihqmomC7jTNRci9UyoEas6CZCCApbIo7XIcVCGM4g3mhkqiNXyILZAZBX3OWNJzYKP4kUxKW1CL8oMhYS8yTDgSdtS0YoZD"
}
{
"grant_type" : "convert_token",
"client_id" :"",
"backend":"kakao",
"token":"Kev3-by9CquBv17E7cIo9eC2MEyb-OJIno6cWQoqAuYAAAFoZyx2AA"
}

Refresh Token

{
"grant_type":"refresh_token",
"client_id":"",
"refresh_token":"fMDnbxKxvtiuSZFuvDElyGR15Ybe3N"
}
โš ๏ธ **GitHub.com Fallback** โš ๏ธ