Django開發支持新浪微博多帳號登錄

fmms 12年前發布 | 57K 次閱讀 Django Web框架

之前曾經寫過一篇文章,講在Django開發中如何整合新浪微博API。當時,新浪微博只支持OAuth1.0,現在已經支持2.0版本,OAuth2.0協議進行了簡化,且access token將不能永久使用,它存在一個過期時間。本文講解了如何在你的django站點中支持多帳號登錄,主要包括Google、新浪微博、人人和騰訊微博帳號,其實就是這個博客目前所支持的第三方帳號登錄。

在這些第三方帳號中,Google、新浪微博以及人人都已經支持了OAuth2.0,而騰訊微博仍然停留在1.0階段。

對于OAuth2.0,以Google帳號為例(Google也支持OpenID方式,讀者可以自己去實現)。

首先,我們在urls中添加登錄以及處理回調的url:

urlpatterns += patterns('myapp.views',
    url(r'^accounts/google/login/$', 'google_login', name='social_google_login'),
    url(r'^accounts/google/login/done/$', 'google_auth', name='social_google_login_done'),
)

登錄地址主要重定向到Google的授權頁面,這在Django中可以直接使用django.views.generic.base.RedirectView這個通用視圖來重定向,不過,由于我們要獲取在授權完成后的重定向地址,也就是初始地址(比如說從/contact/點擊登錄的,最后完成授權后還要重定向到這個url),所以我們在自己定義的views中實現。

獲取初始地址的代碼在先前文章中也出現過,代碼如下:

def _get_referer_url(request):
    referer_url = request.META.get('HTTP_REFERER', '/')
    host = request.META['HTTP_HOST']
    if referer_url.startswith('http') and host not in referer_url:
        referer_url = '/'
    return referer_url

接著定義google_login這個視圖:
import urllib

def google_login(request):
    google_auth_url = '%s?%s' % ('https://accounts.google.com/o/oauth2/auth',
                             urllib.urlencode({
                                 'response_type': 'code',
                                 'client_id': 'Your client id',
                                 'redirect_uri': 'Your redirect uri',
                                 'scope': 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile',
                                 'state': _get_referer_url(request)
                             }))
    return HttpResponseRedirect(google_auth_url)

這里的參數包括response_type,這個對于web應用必須是“code”,它在授權后會重定向到回調地址,并作為參數“code=××××”;client_id和redirect_uri是你在申請Google APIs時所得到或設定的(申請地址,需翻*墻,這里要注意,在這個view中所設定的回調地址必須和申請API時所設定一致);scope是指你要獲得用戶哪方面的權限,這里包括用戶的基本信息以及用戶email地址;state是個可選參數,如果設定,在重定向到回調地址時會作為參數傳遞,這里把初始地址作為state傳遞,在處理回調完成時就可以重定向到這個初始地址。

用戶點擊登錄地址時,就會重定向到Google的授權頁面,如果用戶點擊同意授權,就重定向到你所設定的地址,也就是由google_auth這個視圖在處理。這個時候我們通過request.GET就拿到了code(授權碼)和state(可選)這兩個參數。拿到了授權碼,我們就需要去獲取用戶的 access token:

import urllib2

def get_access_token(code):
    auth_url = 'https://accounts.google.com/o/oauth2/token'
    body = urllib.urlencode({
                'code': code, # 授權碼
                'client_id': 'your client id',
                'client_secret': 'your client_secret',
                'redirect_uri': 'your redirect uri',
                'grant_type': 'authorization_code' # 必須是這個值
                })
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
    }
    req = urllib2.Request(auth_url, body, headers)
    resp = urllib2.urlopen(req)

    data = json.loads(resp.read())

    return data['access_token']

這段代碼非常簡單,通過一系列的參數POST到Google access token endpoint,拿到用戶的access token。接著我們就可以去取到用戶的數據了:
def get_user_info(access_token):
    if access_token:
        userinfo_url = 'https://www.googleapis.com/oauth2/v1/userinfo'
        query_string = urllib.urlencode({'access_token': access_token})

        resp = urllib2.urlopen("%s?%s" % (userinfo_url, query_string))
        data = json.loads(resp.read())

        return data

通過data['name'],data['email'],data['picture']來分別獲取用戶的用戶名、email地址、頭像等等,詳細的返回值可以參考 這里。視圖的代碼如下:
def google_auth(request):
    if 'blog_user' in request.session:
        return HttpResponseRedirect('/')

    if 'error' in request.GET or 'code' not in request.GET:
        return HttpResponseRedirect('/')

    code = request.GET['code']

    access_token = get_access_token(code)
    blog_user = get_blog_user(get_user_info(access_token))

    request.session['blog_user'] = blog_user

    next = '/'
    if 'state' in request.GET:
        next = request.GET['state']

    return HttpResponseRedirect(next)

這里,需要說明的是,在Django中,你可以定義自己的Backend(要在settings中注冊),這樣就可以用通用的方式來進行認證、登錄、登出等操作,詳細參考Authentication文檔。這里沒有這么做,原因有二:一是博客需要保存用戶頭像,而內置的django.contrib.auth.admin.User并沒有這個字段,要么繼承要么用一一對應關系的Model來定義,我也不需要這么復雜,只需要幾個字段以字典的形式保存到request.session中即可;二是得到的 user我也不需要保存到數據庫中,session超時或者用戶自己退出刪除session中的數據即可。

這樣Google帳號的登錄就完成了,可以看到用OAuth2.0還是很簡單的。同樣的,新浪微博和人人都支持2.0方式,他們登錄的操作大同小異,不過有以下注意點。

新浪微博在登錄的地址參數中沒有state這個選項,這就意味著,用戶授權回調的地址中只有code一個參數,所以,在weibo_login這個view中,我們需要把初始地址保存在session中:

request.session['redirect_uri'] = _get_referer_url(request)

另外,要注意,新浪微博的申請時設置回調地址的頁面很坑爹。一個weibo應用包括兩種:”應用“和”網站“。如果你都申請過,你就會發現”網站 “中找不到設置回調地址的地方,但是應用頁面就有,實際上,你需要手動輸入地址:http://open.weibo.com/apps /<your app key>/info/advanced。并且回調地址是不能設置成localhost等等的,它始終會提示你地址不匹配。所以如果要Debug,那么改hosts文件吧……

新浪微博詳細授權方法在這里

人人網有個不同之處,就是它的參數除了一些必備參數,還有個是簽名,簽名就是把所以參數按key從小到大排序,再求MD5值。獲得簽名的代碼如下:

def get_signature(params, secret):
    '''
    param params:字典
    param secret:你申請的app secret
    '''
    params_str = ''.join(['%s=%s'%(k, params[k]) for k in sorted(params)])
    return hashlib.md5("%s%s"%(params_str, secret)).hexdigest()

其他操作大同小異。

騰訊微博這方面就弱多了,官方sdk中不包含Python版本,甚至連推薦也沒有,不過目前做得比較好的是根據推ter python sdk改的SDK(地址文檔)。你可以從源碼,或者用“easy_install -U pyqqweibo”安裝。

方法大致和前一篇新浪微博OAuth1.0方法相同。qqweibo_login代碼如下:

from qqweibo import OAuthHandler, API

def qqweibo_login(request):
    oauth_handler = OAuthHandler('your app key', 'your app_secret', 'redirect uri')
    qqweibo_auth_url = oauth_handler.get_authorization_url() # 得到授權地址
    request.session['redirect_uri'] = _get_referer_url(request) # 保存初始地址
    request.session['request_token'] = (oauth_handler.request_token.key, oauth_handler.request_token.secret)

    return HttpResponseRedirect(qqweibo_auth_url)

騰訊微博中不需要設定回調地址。接著是qqweibo_auth:
def qqweibo_auth(request):
    if 'oauth_verifier' not in request.GET:
        return HttpResponseRedirect('/')

    verifier = request.GET['oauth_verifier']
    request_token = request.session['request_token']
    del request.session['request_token']

    oauth_handler = OAuthHandler('your app key', 'your app_secret', 'redirect uri')
    oauth_handler.set_request_token(request_token[0], request_token[1])
    access_token = oauth_handler.get_access_token(verifier) # 得到access token

    blog_user = get_blog_user(access_token)
    request.session['blog_user'] = blog_user

    next = request.session['redirect_uri']
    del request.session['redirect_uri']

    return HttpResponseRedirect(next)

最后,如果要登出,直接在相應的view中刪除session,并且重定向到來源地址。

好了,關于Django中集成多帳號登錄就介紹這么多了,如果你想看完整代碼,可以參看我的博客項目中social這個app中的代碼。

文章出處:http://qinxuye.me/article/third-party-authentication-in-django/

 本文由用戶 fmms 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!