All Posts Tagged “api”

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)

Facebook Graph API

Facebook Platform Upgrade Guide
https://developers.facebook.com/docs/apps/upgrading/

Access Token

access token 分成:

  • user access token
  • app access token
  • page access token
  • client token

user access token 又分成 short-term 和 long-term
從 mobile app SDK 拿到的都是 long-term
從 web login 拿到的 token 都是 short-term
你可以透過 extending 的方式換成 long-term token
https://developers.facebook.com/docs/facebook-login/access-tokens#extending

不管是從 iOS, Android 或是 Web
只要是在同一個 Facebook app 底下
拿到的 user access token 雖然會不一樣
但是是通用的

如果你要以某個 user 的身份發布動態
你可以使用 user access token
也可以使用 app access token(前題是該 user 有允許過你的 app 的 publish_actions 權限)

ref:
https://developers.facebook.com/docs/facebook-login/access-tokens

Facebook Business Manager

從 2.0 開始就已經拿不到 user 的真實 id 了
只能拿到一個 app-scoped 的 user id
不同的 app 對同一個 user 拿到的 user id 都不一樣
除非這些 app 在同一個 Facebook Business Manager(企業管理平台)的管理下

要使用 Facebook Business Manager
必須要有一個粉絲專頁來作為公司的主要粉絲專頁

ref:
https://developers.facebook.com/docs/apps/upgrading
http://pymaster.logdown.com/post/208417-facebook-platform-versioning

不過其實你可以把同一個 app 用在不同的 domain

Open Graph

Facebook Open Graph 的 action 和 object 有分成 common 和 custom
前者是 Facebook 內建
詳見 https://developers.facebook.com/docs/reference/opengraph
後者是你自己建立的

Common actions do not need to be created, you can just start publishing them. They will then appear in the list of actions in your App Dashboard.

如果你要新增一個跟內建的 object 一樣名稱的 object 的話
Facebook 會告訴你你應該使用內建的
但是其實你可以先隨便新增一個 object
然後進去該 object 的編輯頁面把 object 名稱改成跟內建的一樣
不過審核還是不會過就是了

story 由 action 和 object 組成
如果你只用內建的 action 和 object 的話
不需要自己建立 story

最後記得要把你的 app 有使用到的 permission, action 和 object
提交給 Facebook 審核

現在已經沒有 collection 了
http://stackoverflow.com/questions/18791914/custom-collections-check-if-facebook-user-has-added-it

Story, Action, Object

music.listens
https://developers.facebook.com/docs/reference/opengraph/action-type/music.listens/
https://developers.facebook.com/docs/opengraph/guides/music.listens/

Facebook 不開放一般人使用 music.listens 這個 action
但是你可以自己建立一個 custom action 叫 play 之類的
custom action 還是可以使用 common object
例如下面這些:

music.song
music.playlist
music.musician
https://developers.facebook.com/docs/opengraph/music/
https://developers.facebook.com/docs/reference/opengraph/object-type/music.song/
https://developers.facebook.com/docs/reference/opengraph/object-type/music.playlist/
https://developers.facebook.com/docs/reference/opengraph/object-type/music.musician/

Facebook App 審核

在審核的 screenshots 裡要使用 Open Graph Test User

ref:
https://developers.facebook.com/docs/sharing/best-practices