1. 程式人生 > >用 Flask 來寫個輕部落格 (23) — 應用 OAuth 來實現 Facebook 第三方登入

用 Flask 來寫個輕部落格 (23) — 應用 OAuth 來實現 Facebook 第三方登入

目錄

前文列表

擴充套件閱讀

第三方登入流程

這裡寫圖片描述

Resource Owner:資源所有者,本文中又稱”使用者”(user)。
Authorization server:認證伺服器,即服務提供商專門用來處理認證的伺服器。
Resource server:資源伺服器,即服務提供商存放使用者生成的資源的伺服器。它與認證伺服器,可以是同一臺伺服器,也可以是不同的伺服器。

(A)使用者開啟客戶端以後,客戶端要求使用者給予授權。
(B)使用者同意給予客戶端授權。
(C)客戶端使用上一步獲得的授權,向認證伺服器申請令牌。
(D)認證伺服器對客戶端進行認證以後,確認無誤,同意發放令牌。
(E)客戶端使用令牌,向資源伺服器申請獲取資源。
(F)資源伺服器確認令牌無誤,同意向客戶端開放資源。

不難看出來,上面六個步驟之中,(B) 是整個流程的關鍵,有了這個授權以後,客戶端就可以獲取令牌,進而憑令牌獲取資源。 那使用者怎樣才能給於客戶端授權? 我們可以使用 OAuth 來實現.

OAuth

OAuth 的作用就是讓”客戶端(blog application)”安全可控地獲取”服務商使用者(Facebook User)”帳號的授權,與”服務商提供商(Facebook)”進行互動。

OAuth在”客戶端”與”服務提供商”之間,設定了一個授權層(authorization layer)。”客戶端”不能直接登入”服務提供商”,只能登入授權層,以此將使用者與客戶端分離。”客戶端”登入授權層所用的令牌(token),與使用者的密碼不同。使用者可以在登入的時候,指定授權層令牌的許可權範圍和有效期。

“客戶端”登入授權層以後,”服務提供商”根據令牌的許可權範圍和有效期,向”客戶端”開放使用者儲存的資料。由此可見, 使用者賬戶的安全性就交由這些知名的可靠的”服務提供商”來處理了, 可以更好的降低使用者登入 blog 的信任成本.

應用 OAuth 實現 Facebook 第三方登入

  • 安裝
pip install Flask-OAuth
pip freeze > requirements.txt
  • 初始化 OAuth 物件, 並使用該物件來獲取 facebook 物件
    vim extensions.py

from flask_oauth import
OAuth # Create the Flask-OAuth's instance oauth = OAuth() # facebook 第三方登入介面 # Create the auth object for facebook. facebook = oauth.remote_app( 'facebook', base_url='https://graph.facebook.com/', request_token_url=None, access_token_url='/oauth/access_token', authorize_url='https://www.facebook.com/dialog/oauth', consumer_key='<Your_app_number>', consumer_secret='<Your_app_secret>', request_token_params={'scope': 'email'}) @facebook.tokengetter def get_facebook_token(): return session.get('facebook_oauth_token')

NOTE 1: facebook 物件是上述步驟中建立的 facebook 應用物件, 其包含了認證的結果資訊和請求授權的 facebook user 資訊. facebook 是完成第三方登入流程的介面物件.

NOTE 2: 方法 get_facebook_oauth_token() 獲取 facebook 發放的 token. 當成功建立 facebook 物件並完成授權時, 表示 client(blog) 成功的向 Authorization server 完成認證並接受到服務端的 token, 並儲存在 session 中. 然後 Client 就可以使用這個 token 去訪問 facebook 的資源(賬戶許可權資源)了.

  • 實現在 client 觸發使用者授權的邏輯
    vim jmilkfansblog/controllers/main.py
from jmilkfansblog.extensions import openid, facebook


# 當訪問 /facebook 時, 觸發授權流程
main_blueprint.route('/facebook')
def facebook_login():
    return facebook.authorize(
        callback=url_for('main.facebook_authorized',
                         next=request.referrer or None,
                         _external=True))


# 該檢視會接受從 facebook 認證伺服器返回的 resp 物件, 可以通過 resp 物件來判斷 Client 在 Server 上的認證結果.
@main_blueprint.route('/facebook/authorized')
@facebook.authorized_handler
def facebook_authorized(resp):
    if resp is None:
        return 'Access denied: reason=%s error=%s' % (
            request.args['error_reason'],
            request.args['error_description'])

    session['facebook_oauth_token'] = (resp['access_token'], '')

    me = facebook.get('/me')

    if me.data.get('first_name', False):
        facebook_username = me.data['first_name'] + " " + me.data['last_name']
    else:
        facebook_username = me.data['name']

    user = User.query.filter_by(username=facebook_username).first()
    if user is None:
        user = User(id=str(uuid4()), username=facebook_username, password='jmilkfan')
        db.session.add(user)
        db.session.commit()

    flash('You have been logged in.', category='success')

    return redirect(url_for('blog.home'))
  • 實現登入連結
<div class="row">
  <div class="form-group">
    <a href="{{ url_for('main.facebook_login') }}">Login via Facebook</a>
  </div>
</div>

實現效果

訪問 /faceboook/authorized 進入使用者授權頁面:
這裡寫圖片描述
NOTE: 需要首先登入到 facebook 之後, 才能夠進入授權的處理流程.

授權並登入成功:
這裡寫圖片描述