45
loading...
This website collects cookies to deliver better user experience
OAuth 命名 |
Twitter 命名 |
Authlib 命名 |
用途 |
---|---|---|---|
Service Provider | OAuth Server | 提供 OAuth 認證的平台 | |
Consumer | App | OAuth Client | 向 OAuth server 要求認證的 app |
Consumer Key | API Key | Client ID | 存取 Twitter API |
Consumer Secret | API Secret Key | Client Secret | 產生 HMAC-SHA1 防偽簽名 |
Callback | Callback URL | Redirct URI | 用戶認證後 Twitter 把用戶導向 app 的網址 |
authlib
元件及定義一些基礎參數:from authlib.integrations.requests_client import OAuth1Session
client_id: str = 'my_client_id' # TWITTER_API_KEY
client_secret: str = 'my_client_secret' # TWITTER_API_SECRET_KEY
client: OAuthSession = OAuth1Session(
client_id = client_id,
client_secret = client_secret
)
client
與 Twitter API 做交流。上面的 client_id
與 client_secret
的值比較正規的做法應該用 python-dotenv 隱藏起來,但這裡就不講究那麼多了。client
去向 Twitter API 取得 request_token
:request_token_url: str = 'https://api.twitter.com/oauth/request_token'
request_token:dict = client.fetch_request_token(url=request_token_url)
print(request_token)
# request_token
{
'oauth_token' : 'my_oauth_token',
'oauth_token_secret' : 'my_auth_token_secret',
'oauth_callback_confirmed' : 'true'
}
from authlib.integrations.requests_client import OAuth1Session
client_id: str = 'my_client_id' # TWITTER_API_KEY
client_secret: str = 'my_client_secret' # TWITTER_API_SECRET_KEY
redirect_uri = 'https://staging.example.com/auth/twitter'
client: OAuthSession = OAuth1Session(
client_id = client_id,
client_secret = client_secret,
redirect_uri = redirect_uri
)
redirect_uri
的網址也還是得要事先登錄到 Twitter Developer Portal 的 Callback URLs,否則是會被 Twitter API 阻擋的。request_token
去組出一個 Twitter 用戶認證網址:oauth_token: str = request_token['oauth_token']
oauth_token_secret: str = request_token['oauth_token_secret']
authenticate_url: str = 'https://api.twitter.com/oauth/authenticate'
client.create_authorization_url(
url = authenticate_url,
request_token = oauth_token
)
# Authorization URL
'https://api.twitter.com/oauth/authenticate?oauth_token=my_oauth_token'
oauth_token
與 oauth_verifier
。https://example.com/auth/twitter
,Twitter 導引用戶回來時會在 callback URL 後附加 oauth_token
與 oauth_verifier
兩個參數,因此收到的請求是這樣的:resp_url: str = 'https://example.com/auth/twitter?oauth_token=my_oauth_token&oauth_verifier=my_oauth_verifier'
oauth_token
與 oauth_verifier
去向 Twitter API 要 access token:client.parse_authorization_response(resp_url)
access_token_url: str = 'https://api.twitter.com/oauth/access_token'
token: dict = client.fetch_access_token(access_token_url)
print(token)
# token
{
'oauth_token' : 'user_oauth_token',
'oauth_token_secret': 'user_oauth_token_secret',
'user_id' : 'user_user_id',
'screen_name' : 'user_screen_name'
}
oauth_token
和 oauth_token_secret
是代表那位用戶的,而在此之前和 Twitter API 交互的 oauth_token
是屬於我們的 app 的,名字一樣但意義不同。oauth_token
、oauth_token_secret
、user_id
、screen_name
應該存入我們自己的會員資料庫內,做為後續認證之用,但要注意的是不要拿 screen_name
辨識用戶,因為 Twitter 的用戶名是可以改的。verify_credentials
這支 API:twitter_account_verify_credentials_uri = 'https://api.twitter.com/1.1/account/verify_credentials.json'
resp = client.get(
url = twitter_account_verify_credentials_uri,
params = {'skip_status': True}
)
print(resp.json())
# resp.json()
{
...
'protected': False,
'friends_count': 5,
'favourites_count': 9,
'utc_offset': None,
'time_zone': None,
'geo_enabled': False,
'verified': False,
'statuses_count': 7,
'lang': None,
'contributors_enabled': False,
'is_translator': False,
'is_translation_enabled': False,
'profile_background_tile': False,
'profile_use_background_image': True,
'has_extended_profile': True,
'default_profile': True,
'default_profile_image': False,
'following': False,
'follow_request_sent': False,
'notifications': False,
'translator_type': 'none',
'suspended': False,
'needs_phone_verification': False,
...
}
from starlette.applications import Starlette
from starlette.requests import Request
app = Starlette()
authlib
的元件及初始化:from starlette.applications import Starlette
from starlette.requests import Request
from authlib.integrations.starlette_client import OAuth
app = Starlette()
oauth = OAuth()
from starlette.applications import Starlette
from starlette.requests import Request
from authlib.integrations.starlette_client import OAuth
app = Starlette()
oauth = OAuth()
oauth.register(
name = 'twitter',
api_base_url = 'https://api.twitter.com/1.1/',
request_token_url = 'https://api.twitter.com/oauth/request_token',
request_token_params = None,
access_token_url = 'https://api.twitter.com/oauth/access_token',
access_token_params = None,
authorize_url = 'https://api.twitter.com/oauth/authenticate',
aurhorize_params = None,
client_id = 'my_client_id',
client_secret = 'my_client_secret',
client_kwargs = None,
)
request_token_url
、access_token_url
、authorize_url
,也必然會有 client_id
、client_secret
兩個值,儘管命名可能不一樣。client_id
、client_secret
的值應該要放在 .env 內,這裡只是示範才省略。from starlette.applications import Starlette
from starlette.requests import Request
from authlib.integrations.starlette_client import OAuth
app = Starlette()
oauth = OAuth()
oauth.register(
name = 'twitter',
api_base_url = 'https://api.twitter.com/1.1/',
request_token_url = 'https://api.twitter.com/oauth/request_token',
request_token_params = None,
access_token_url = 'https://api.twitter.com/oauth/access_token',
access_token_params = None,
authorize_url = 'https://api.twitter.com/oauth/authenticate',
aurhorize_params = None,
client_id = 'my_client_id',
client_secret = 'my_client_secret',
client_kwargs = None,
)
@app.route('/login/twitter')
async def login_via_twitter(request: Request):
twitter = oauth.create_client('twitter')
redirect_uri = request.url_for('authorize_twitter')
return await twitter.authorize_redirect(request, redirect_uri)
@app.route('/auth/twitter')
async def authorize_twitter(request: Request):
twitter = oauth.create_client('twitter')
token = await twitter.authorize_access_token(request)
user = await twitter.parse_id_token(request, token)
return user
authorize_redirect()
就把拿 request token 和導引用戶到 Twitter 認證頁的工作全做掉了,後面的 callback 網址收到 Twitter 導回來的用戶也是一個函式 authorize_access_token()
搞定前面手動拿 token 交換來交換去的工作,真心感謝 Authlib 大大,祝 Authlib 大大好人一生平安。from starlette.applications import Starlette
from starlette.requests import Request
from starlette.middleware.sessions import SessionMiddleware
from authlib.integrations.starlette_client import OAuth
app = Starlette()
app.add_middleware(SessionMiddleware, secret_key="㊙️")
oauth = OAuth()
oauth.register(
name = 'twitter',
api_base_url = 'https://api.twitter.com/1.1/',
request_token_url = 'https://api.twitter.com/oauth/request_token',
request_token_params = None,
access_token_url = 'https://api.twitter.com/oauth/access_token',
access_token_params = None,
authorize_url = 'https://api.twitter.com/oauth/authenticate',
aurhorize_params = None,
client_id = 'my_client_id',
client_secret = 'my_client_secret',
client_kwargs = None,
)
@app.route('/login/twitter')
async def login_via_twitter(request: Request):
twitter = oauth.create_client('twitter')
redirect_uri = request.url_for('authorize_twitter')
return await twitter.authorize_redirect(request, redirect_uri)
@app.route('/auth/twitter')
async def authorize_twitter(request: Request):
twitter = oauth.create_client('twitter')
token = await twitter.authorize_access_token(request)
user = await twitter.parse_id_token(request, token)
return user
register()
authorize_redirect()
authorize_access_token()