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 中使用(並清除),以達到安全目的。

此方法為非同步,必須使用 awaityield 呼叫 (這與此模組中定義的其他 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,其中包含鍵 keysecret

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 的抽象實作。

請參閱下面的 FacebookGraphMixinGoogleOAuth2Mixin 以瞭解實作範例。

類別屬性

  • _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 中,它將從字串變為整數。

  • idnamefirst_namelast_namelocalepicturelink,以及在 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_redirectget_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_keytwitter_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 返回的使用者物件包含屬性 usernamenameaccess_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_redirectget_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 引數已移除。請改用傳回的可等待物件。