All Posts Tagged “oauth”

Build an Oauth 2.0 provider with django-oauth-toolkit

What is Oauth?
http://coding.anyun.tw/2012/03/13/oauth-2/
http://blog.yorkxin.org/posts/2013/09/30/oauth2-1-introduction

Install

$ pip install djangorestframework django-oauth-toolkit

Configuration

in settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'api.authentications.SVOauthAuthentication',
        'api.authentications.SVTokenAuthentication',
        'api.authentications.SVAppAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ],
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ],
    'PAGINATE_BY': 10,
    'PAGINATE_BY_PARAM': 'page_size',
    'MAX_PAGINATE_BY': 100,
    'EXCEPTION_HANDLER': 'api.exceptions.sv_exception_handler',
}

OAUTH2_PROVIDER_APPLICATION_MODEL = 'api.Application'

OAUTH2_PROVIDER = {
    'AUTHORIZATION_CODE_EXPIRE_SECONDS': 60 * 60,
    'ACCESS_TOKEN_EXPIRE_SECONDS': 60 * 60 * 24 * 7,
    'SCOPES': {
        'read': 'Read scope',
        'write': 'Write scope',
    }
}

in models.py

你可能會需要一個自己的 Application model

from oauth2_provider.models import AbstractApplication

class Application(AbstractApplication):
    logo = models.ImageField(_(u'LOGO'), upload_to=utils.unique_path('app_logo/'), storage=svmedia_storage, null=True, blank=True)
    identity = models.PositiveSmallIntegerField(choices=api_settings.IDENTITY_CHOICES, db_index=True)

    class Meta:
        verbose_name = _('Application')
        verbose_name_plural = _('Applications')
        unique_together = (('client_id', 'client_secret'), )

    def __unicode__(self):
        return self.name

ref:
https://django-oauth-toolkit.readthedocs.org/
http://tomchristie.github.io/rest-framework-2-docs/api-guide/authentication#oauthauthentication

in urls.py

url(r'^oauth/', include('oauth2_provider.urls', namespace='oauth2_provider')),

Usage

註冊 application(也稱為 client)

client type:

confidential: Client 可以自我保密 client 的 credentials(例如跑在 Server 上面,且可以限制 credentials 的存取),或是可以用別的手段來確保認證過程的安全性。
public: Client 無法保密 credentials (Native App 或是跑在 Browser 裡面的 App),或是無法用任何手段來保護 client 的認證。

grant type:

authorization code: 最常用的方式,先拿到 authorization code 之後,再用它去換 access token 和 refresh token
implicit: Authorization Server 直接向 Client 核發 Access Token ,而不像 Authorization Code Grant Flow ,先核發 Grant ,再另外去拿 Access Token。
resource owner password-based: 直接拿用戶的帳號、密碼來換 access token
client credentials: 只使用 client id 和 client secret 來換 access token

ref:
http://blog.yorkxin.org/posts/2013/09/30/oauth2-2-cilent-registration/

獲得 access token

第一步:

GET:
http://local.streetvoice.com:8001/oauth/authorize/?client_id=6d01bea01ab7e46eace3&response_type=code&scope=read%20write&redirect_uri=http://local.packer.streetvoice.com:8003/process_oauth/

client_id=6d01bea01ab7e46eace3&
response_type=code&
scope=read%20write&
state=optional&
redirect_uri=http://local.packer.streetvoice.com:8003/process_oauth/

scope 要以空格分開

Response:
http://local.packer.streetvoice.com:8003/process_oauth/?code=lJvivguZOGFghSxjIzpRHdnwH2opwP

第二步:

POST:
http://local.streetvoice.com:8001/oauth/token/?client_id=6d01bea01ab7e46eace3&grant_type=authorization_code&code=lJvivguZOGFghSxjIzpRHdnwH2opwP&redirect_uri=http://local.packer.streetvoice.com:8003/process_oauth/

client_id=6d01bea01ab7e46eace3&
grant_type=authorization_code&
code=lJvivguZOGFghSxjIzpRHdnwH2opwP&
redirect_uri=http://local.packer.streetvoice.com:8003/process_oauth/

Response:

{
    "access_token": "KwB2XADuQVzcGYCFC7TzfP67NBn9Ud",
    "token_type": "Bearer",
    "expires_in": 604800,
    "refresh_token": "2kiVHEAKWNn7U57YFIw0TqXgVN1TQW",
    "scope": "read write"
}

ref:
http://blog.yorkxin.org/posts/2013/09/30/oauth2-4-1-auth-code-grant-flow/

刷新 access token

POST:
http://local.streetvoice.com:8001/oauth/token/?client_id=6d01bea01ab7e46eace3&grant_type=refresh_token&refresh_token=2kiVHEAKWNn7U57YFIw0TqXgVN1TQW&scope=read%20write

client_id=6d01bea01ab7e46eace3&
grant_type=refresh_token&
refresh_token=2kiVHEAKWNn7U57YFIw0TqXgVN1TQW&
scope=read%20write

Response:

{
    "access_token": "NGJ29T95qonMRKO91at6Oroke1d0J6",
    "token_type": "Bearer",
    "expires_in": 604800,
    "refresh_token": "WujMQX8GU4dd1obXDpG5quDxiIbbV7",
    "scope": "read write"
}

使用 access token

$ curl -H "Authorization: Bearer NGJ29T95qonMRKO91at6Oroke1d0J6" -X GET http://local.streetvoice.com:8001/api/v1/auth/me/
import requests

url = 'http://local.streetvoice.com:8001/api/v1/auth/me/'
headers = {
    'Authorization': 'Bearer NGJ29T95qonMRKO91at6Oroke1d0J6',
}
r = requests.get(url, headers=headers)
print(r.content)