tornado.auth
— 使用 OpenID 和 OAuth 的第三方登入¶
這個模組包含各種第三方身份驗證方案的實作。
此檔案中的所有類別都是類別混合,旨在與 tornado.web.RequestHandler
類別一起使用。它們以兩種方式使用
在登入處理程序上,使用諸如
authenticate_redirect()
、authorize_redirect()
和get_authenticated_user()
等方法來建立使用者身分,並將驗證權杖儲存到資料庫和/或 Cookie 中。在非登入處理程序中,使用諸如
facebook_request()
或twitter_request()
等方法,以使用驗證權杖向各自的服務發出請求。
由於所有這些服務實作驗證和授權的方式略有不同,因此它們都採用略有不同的參數。有關完整的說明文件,請參閱以下各個服務類別。
Google OAuth 的範例用法
class GoogleOAuth2LoginHandler(tornado.web.RequestHandler,
tornado.auth.GoogleOAuth2Mixin):
async def get(self):
# Google requires an exact match for redirect_uri, so it's
# best to get it from your app configuration instead of from
# self.request.full_uri().
redirect_uri = urllib.parse.urljoin(self.application.settings['redirect_base_uri'],
self.reverse_url('google_oauth'))
async def get(self):
if self.get_argument('code', False):
access = await self.get_authenticated_user(
redirect_uri=redirect_uri,
code=self.get_argument('code'))
user = await self.oauth2_request(
"https://www.googleapis.com/oauth2/v1/userinfo",
access_token=access["access_token"])
# Save the user and access token. For example:
user_cookie = dict(id=user["id"], access_token=access["access_token"])
self.set_signed_cookie("user", json.dumps(user_cookie))
self.redirect("/")
else:
self.authorize_redirect(
redirect_uri=redirect_uri,
client_id=self.get_google_oauth_settings()['key'],
scope=['profile', 'email'],
response_type='code',
extra_params={'approval_prompt': 'auto'})
常見協定¶
這些類別實作 OpenID 和 OAuth 標準。一般而言,它們需要被子類化才能與任何特定網站一起使用。所需自訂的程度會有所不同,但在大多數情況下,覆寫類別屬性(由於歷史原因,這些屬性的名稱以底線開頭)就足夠了。
- class tornado.auth.OpenIdMixin[原始碼]¶
OpenID 和屬性交換的抽象實作。
類別屬性
_OPENID_ENDPOINT
: 身份提供者的 URI。
- authenticate_redirect(callback_uri: Optional[str] = None, ax_attrs: List[str] = ['name', 'email', 'language', 'username']) None [原始碼]¶
重新導向至此服務的驗證 URL。
驗證後,服務將使用其他參數(包括
openid.mode
)重新導向回指定的callback URI。依預設,我們會要求驗證使用者提供的屬性(姓名、電子郵件、語言和使用者名稱)。如果您的應用程式不需要所有這些屬性,您可以使用 ax_attrs 關鍵字引數來要求較少的屬性。
在 6.0 版本中變更:
callback
引數已移除,此方法不再傳回可等待物件。它現在是一個普通的同步函式。
- coroutine get_authenticated_user(http_client: Optional[AsyncHTTPClient] = None) Dict[str, Any] [原始碼]¶
在重新導向時擷取已驗證的使用者資料。
這個方法應該由接收來自
authenticate_redirect()
方法的重新導向的處理程序呼叫(通常與呼叫它的處理程序相同;在這種情況下,如果存在openid.mode
參數,您會呼叫get_authenticated_user
,如果不存在,則會呼叫authenticate_redirect
)。這個方法的結果通常會用於設定 Cookie。
在 6.0 版本中變更:
callback
引數已移除。請改用傳回的可等待物件。
- get_auth_http_client() AsyncHTTPClient [原始碼]¶
傳回要用於驗證請求的
AsyncHTTPClient
執行個體。子類別可能會覆寫此方法以使用預設以外的 HTTP 用戶端。
- class tornado.auth.OAuthMixin[原始碼]¶
OAuth 1.0 和 1.0a 的抽象實作。
有關範例實作,請參閱以下
TwitterMixin
。類別屬性
_OAUTH_AUTHORIZE_URL
: 服務的 OAuth 授權 URL。_OAUTH_ACCESS_TOKEN_URL
: 服務的 OAuth 存取權杖 URL。_OAUTH_VERSION
: 可以是「1.0」或「1.0a」。_OAUTH_NO_CALLBACKS
: 如果服務需要預先註冊回呼,請將此設定為 True。
子類別也必須覆寫
_oauth_get_user_future
和_oauth_consumer_token
方法。- async authorize_redirect(callback_uri: Optional[str] = None, extra_params: Optional[Dict[str, Any]] = None, http_client: Optional[AsyncHTTPClient] = None) None [原始碼]¶
將使用者重新導向以取得此服務的 OAuth 授權。
如果先前已向第三方服務註冊回呼 URI,則可以省略
callback_uri
。對於某些服務,您必須使用先前註冊的回呼 URI,而無法透過此方法指定回呼。此方法會設定一個名為
_oauth_request_token
的 Cookie,該 Cookie 後續會在get_authenticated_user
中使用(並清除),以達到安全目的。此方法為非同步,必須使用
await
或yield
呼叫 (這與此模組中定義的其他auth*_redirect
方法不同)。它會為您呼叫RequestHandler.finish
,因此您不應在它返回後寫入任何其他回應。變更於 3.1 版本:現在返回
Future
並採用選用的回呼,以便與gen.coroutine
相容。在 6.0 版本中變更:
callback
引數已移除。請改用傳回的可等待物件。
- async get_authenticated_user(http_client: Optional[AsyncHTTPClient] = None) Dict[str, Any] [原始碼]¶
取得 OAuth 授權的使用者和存取權杖。
應該從您的 OAuth 回呼 URL 的處理常式中呼叫此方法,以完成註冊程序。我們會使用經過身份驗證的使用者字典執行回呼。此字典將包含一個
access_key
,可用於代表使用者向此服務發出授權請求。該字典還將包含其他欄位,例如name
,具體取決於所使用的服務。在 6.0 版本中變更:
callback
引數已移除。請改用傳回的可等待物件。
- _oauth_consumer_token() Dict[str, Any] [原始碼]¶
子類別必須覆寫此方法以傳回其 OAuth 消費者金鑰。
傳回值應該是一個
dict
,其中包含鍵key
和secret
。
- async _oauth_get_user_future(access_token: Dict[str, Any]) Dict[str, Any] [原始碼]¶
子類別必須覆寫此方法以取得有關使用者的基本資訊。
應該是一個協程,其結果是一個字典,其中包含有關使用者的資訊,這些資訊可能是透過使用
access_token
向服務發出請求而檢索到的。存取權杖將被新增到返回的字典中,以形成
get_authenticated_user
的結果。變更於 5.1 版本:子類別也可以使用
async def
定義此方法。變更於 6.0 版本:已移除對
_oauth_get_user
的同步回退。
- get_auth_http_client() AsyncHTTPClient [原始碼]¶
傳回要用於驗證請求的
AsyncHTTPClient
執行個體。子類別可能會覆寫此方法以使用預設以外的 HTTP 用戶端。
- class tornado.auth.OAuth2Mixin[原始碼]¶
OAuth 2.0 的抽象實作。
請參閱下面的
FacebookGraphMixin
或GoogleOAuth2Mixin
以瞭解實作範例。類別屬性
_OAUTH_AUTHORIZE_URL
: 服務的授權 URL。_OAUTH_ACCESS_TOKEN_URL
: 服務的存取權杖 URL。
- authorize_redirect(redirect_uri: Optional[str] = None, client_id: Optional[str] = None, client_secret: Optional[str] = None, extra_params: Optional[Dict[str, Any]] = None, scope: Optional[List[str]] = None, response_type: str = 'code') None [原始碼]¶
將使用者重新導向以取得此服務的 OAuth 授權。
有些供應商要求您向應用程式註冊重新導向 URL,而不是透過此方法傳遞。您應該呼叫此方法以登入使用者,然後在重新導向 URL 的處理常式中呼叫
get_authenticated_user
來完成授權程序。變更於 6.0 版本: 移除了
callback
參數和傳回的可等待對象;現在這是一個普通的同步函式。自 6.4 版本起已棄用:
client_secret
參數(從未有任何作用)已棄用,將在 Tornado 7.0 中移除。
- 協程 oauth2_request(url: str, access_token: Optional[str] = None, post_args: Optional[Dict[str, Any]] = None, **args: Any) Any [原始碼]¶
使用 OAuth2 存取權杖提取指定的 URL。
如果請求是 POST,則應提供
post_args
。查詢字串參數應作為關鍵字引數提供。使用範例
..testcode
class MainHandler(tornado.web.RequestHandler, tornado.auth.FacebookGraphMixin): @tornado.web.authenticated async def get(self): new_entry = await self.oauth2_request( "https://graph.facebook.com/me/feed", post_args={"message": "I am posting from my Tornado application!"}, access_token=self.current_user["access_token"]) if not new_entry: # Call failed; perhaps missing permission? self.authorize_redirect() return self.finish("Posted a message!")
4.3 版本新增。
- get_auth_http_client() AsyncHTTPClient [原始碼]¶
傳回要用於驗證請求的
AsyncHTTPClient
執行個體。子類別可能會覆寫此方法以使用預設以外的 HTTP 用戶端。
4.3 版本新增。
Google¶
- class tornado.auth.GoogleOAuth2Mixin[原始碼]¶
使用 OAuth2 的 Google 身份驗證。
為了使用,請向 Google 註冊您的應用程式,並將相關參數複製到您的應用程式設定。
前往 Google 開發人員控制台,網址為 http://console.developers.google.com
選取專案或建立新專案。
根據所需的權限,您可能需要將您的應用程式設定為「測試」模式,並將您的帳戶新增為測試使用者,或完成驗證程序。您可能還需要使用「啟用 API 和服務」命令來啟用特定服務。
在左側的側邊欄中,選取「憑證」。
點擊「建立憑證」,然後點擊「OAuth 用戶端 ID」。
在「應用程式類型」下,選取「網頁應用程式」。
命名 OAuth 2.0 用戶端並點擊「建立」。
將「用戶端密碼」和「用戶端 ID」複製到應用程式設定,格式為
{"google_oauth": {"key": CLIENT_ID, "secret": CLIENT_SECRET}}
您必須在「憑證」頁面上註冊您計畫與此類別一起使用的
redirect_uri
。
3.2 版本新增。
- get_google_oauth_settings() Dict[str, str] [原始碼]¶
傳回您使用 [Google Cloud Platform](https://console.cloud.google.com/apis/credentials) 建立的 Google OAuth 2.0 憑證。字典格式為
{ "key": "your_client_id", "secret": "your_client_secret" }
如果您的憑證以不同的方式儲存(例如在資料庫中),您可以覆寫此方法以進行自訂佈建。
- 協程 get_authenticated_user(redirect_uri: str, code: str, client_id: Optional[str] = None, client_secret: Optional[str] = None) Dict[str, Any] [原始碼]¶
處理 Google 使用者的登入,並返回一個存取令牌。
結果是一個包含
access_token
欄位的字典([以及其他欄位](https://developers.google.com/identity/protocols/OAuth2WebServer#handlingtheresponse))。與此套件中其他get_authenticated_user
方法不同,此方法不會返回任何關於使用者的其他資訊。返回的存取令牌可以與OAuth2Mixin.oauth2_request
一起使用,以請求其他資訊(可能來自https://www.googleapis.com/oauth2/v2/userinfo
)。使用範例
class GoogleOAuth2LoginHandler(tornado.web.RequestHandler, tornado.auth.GoogleOAuth2Mixin): async def get(self): # Google requires an exact match for redirect_uri, so it's # best to get it from your app configuration instead of from # self.request.full_uri(). redirect_uri = urllib.parse.urljoin(self.application.settings['redirect_base_uri'], self.reverse_url('google_oauth')) async def get(self): if self.get_argument('code', False): access = await self.get_authenticated_user( redirect_uri=redirect_uri, code=self.get_argument('code')) user = await self.oauth2_request( "https://www.googleapis.com/oauth2/v1/userinfo", access_token=access["access_token"]) # Save the user and access token. For example: user_cookie = dict(id=user["id"], access_token=access["access_token"]) self.set_signed_cookie("user", json.dumps(user_cookie)) self.redirect("/") else: self.authorize_redirect( redirect_uri=redirect_uri, client_id=self.get_google_oauth_settings()['key'], scope=['profile', 'email'], response_type='code', extra_params={'approval_prompt': 'auto'})
在 6.0 版本中變更:
callback
引數已移除。請改用傳回的可等待物件。
Facebook¶
- 類別 tornado.auth.FacebookGraphMixin[原始碼]¶
使用新的 Graph API 和 OAuth2 進行 Facebook 驗證。
- 協程 get_authenticated_user(redirect_uri: str, client_id: str, client_secret: str, code: str, extra_fields: Optional[Dict[str, Any]] = None) Optional[Dict[str, Any]] [原始碼]¶
處理 Facebook 使用者的登入,並返回一個使用者物件。
使用範例
class FacebookGraphLoginHandler(tornado.web.RequestHandler, tornado.auth.FacebookGraphMixin): async def get(self): redirect_uri = urllib.parse.urljoin( self.application.settings['redirect_base_uri'], self.reverse_url('facebook_oauth')) if self.get_argument("code", False): user = await self.get_authenticated_user( redirect_uri=redirect_uri, client_id=self.settings["facebook_api_key"], client_secret=self.settings["facebook_secret"], code=self.get_argument("code")) # Save the user with e.g. set_signed_cookie else: self.authorize_redirect( redirect_uri=redirect_uri, client_id=self.settings["facebook_api_key"], extra_params={"scope": "user_posts"})
此方法返回一個字典,其中可能包含以下欄位
access_token
,一個字串,可以傳遞給facebook_request
session_expires
,一個以字串編碼的整數,表示存取令牌在幾秒鐘內過期的時間。此欄位應像int(user['session_expires'])
一樣使用;在未來版本的 Tornado 中,它將從字串變為整數。id
、name
、first_name
、last_name
、locale
、picture
、link
,以及在extra_fields
參數中命名的任何欄位。這些欄位是從 Facebook graph API 使用者物件 複製的。
在 4.5 版本中變更:
session_expires
欄位已更新,以支援 2017 年 3 月對 Facebook API 所做的變更。在 6.0 版本中變更:
callback
引數已移除。請改用傳回的可等待物件。
- 協程 facebook_request(path: str, access_token: Optional[str] = None, post_args: Optional[Dict[str, Any]] = None, **args: Any) Any [原始碼]¶
獲取給定的相對 API 路徑,例如 “/btaylor/picture”
如果請求是 POST,則應提供
post_args
。查詢字串參數應作為關鍵字引數提供。Facebook Graph API 的簡介可以在 http://developers.facebook.com/docs/api 找到。
許多方法需要 OAuth 存取權杖,您可以使用
authorize_redirect
和get_authenticated_user
來取得。透過該流程返回的使用者包含一個access_token
屬性,可用於透過此方法發出已驗證的請求。使用範例
class MainHandler(tornado.web.RequestHandler, tornado.auth.FacebookGraphMixin): @tornado.web.authenticated async def get(self): new_entry = await self.facebook_request( "/me/feed", post_args={"message": "I am posting from my Tornado application!"}, access_token=self.current_user["access_token"]) if not new_entry: # Call failed; perhaps missing permission? self.authorize_redirect() return self.finish("Posted a message!")
給定的路徑是相對於
self._FACEBOOK_BASE_URL
,預設為「https://graph.facebook.com」。此方法是
OAuth2Mixin.oauth2_request
的包裝器;唯一的區別在於此方法接受相對路徑,而oauth2_request
接受完整的 URL。在 3.1 版本變更:新增覆寫
self._FACEBOOK_BASE_URL
的能力。在 6.0 版本中變更:
callback
引數已移除。請改用傳回的可等待物件。
Twitter¶
- class tornado.auth.TwitterMixin[原始碼]¶
Twitter OAuth 驗證。
若要使用 Twitter 進行驗證,請在 http://twitter.com/apps 上註冊您的應用程式。然後將您的消費者金鑰和消費者密鑰複製到應用程式的
settings
中,分別為twitter_consumer_key
和twitter_consumer_secret
。在您註冊為應用程式回呼 URL 的 URL 的處理常式上使用此混入。設定好應用程式後,您可以使用此混入來透過 Twitter 驗證使用者,並取得他們的串流的存取權限。
class TwitterLoginHandler(tornado.web.RequestHandler, tornado.auth.TwitterMixin): async def get(self): if self.get_argument("oauth_token", None): user = await self.get_authenticated_user() # Save the user using e.g. set_signed_cookie() else: await self.authorize_redirect()
由
get_authenticated_user
返回的使用者物件包含屬性username
、name
、access_token
,以及 https://dev.twitter.com/docs/api/1.1/get/users/show 中描述的所有自訂 Twitter 使用者屬性。自 6.3 版本起已棄用:此類別參考 Twitter API 的 1.1 版本,該版本已被 Twitter 棄用。由於 Twitter 已開始限制對其 API 的存取,此類別將不再更新,並將在未來移除。
- coroutine authenticate_redirect(callback_uri: Optional[str] = None) None [原始碼]¶
就像
authorize_redirect
一樣,但如果已授權,則會自動重新導向。如果您使用 Twitter 進行單一登入,這通常是正確的介面。
變更於 3.1 版本:現在返回
Future
並採用選用的回呼,以便與gen.coroutine
相容。在 6.0 版本中變更:
callback
引數已移除。請改用傳回的可等待物件。
- coroutine twitter_request(path: str, access_token: Dict[str, Any], post_args: Optional[Dict[str, Any]] = None, **args: Any) Any [原始碼]¶
擷取指定的 API 路徑,例如
statuses/user_timeline/btaylor
路徑不應包含格式或 API 版本號碼。(我們會自動使用 JSON 格式和 API 版本 1)。
如果請求是 POST,則應提供
post_args
。查詢字串參數應作為關鍵字引數提供。所有 Twitter 方法都記錄在 http://dev.twitter.com/
許多方法需要 OAuth 存取權杖,您可以使用
authorize_redirect
和get_authenticated_user
來取得。透過該流程返回的使用者包含一個 'access_token' 屬性,可用於透過此方法發出已驗證的請求。範例用法class MainHandler(tornado.web.RequestHandler, tornado.auth.TwitterMixin): @tornado.web.authenticated async def get(self): new_entry = await self.twitter_request( "/statuses/update", post_args={"status": "Testing Tornado Web Server"}, access_token=self.current_user["access_token"]) if not new_entry: # Call failed; perhaps missing permission? await self.authorize_redirect() return self.finish("Posted a message!")
在 6.0 版本中變更:
callback
引數已移除。請改用傳回的可等待物件。