2013-07-20 83 views
1

我想通過我的Django網站上的Github進行身份驗證。這是我想出了:關於Github OAuth身份驗證

import string 
import random 
import urllib 

from django.conf import settings 
from django.core.urlresolvers import reverse 
from django.shortcuts import redirect 
from django.utils.crypto import constant_time_compare 
from django.contrib.auth import login 

from rauth import OAuth2Service 
from mongoengine.django.auth import User 

from utils import make_absolute 


SESSION_KEY = '_oauth_access_token' 
SESSION_STATE = '_oauth_state' 

github = OAuth2Service(
    client_id=settings.GITHUB_APP_ID, 
    client_secret=settings.GITHUB_API_SECRET, 
    name='github', 
    authorize_url='https://github.com/login/oauth/authorize', 
    access_token_url='https://github.com/login/oauth/access_token', 
    base_url='http://github.com/') 


def random_string(): 
    return ''.join(random.choice(string.ascii_letters + string.digits) 
        for _ in xrange(random.randint(27, 49))) 


def flush_and_set(request, key, value): 
    if key in request.session: 
     if request.session[key] != value: 
      request.session.flush() 
    else: 
     request.session.cycle_key() 
    request.session[key] = value 


def start_pipeline(request): 
    state = random_string() 
    flush_and_set(request, SESSION_STATE, state) 
    return redirect(github.get_authorize_url(
         redirect_uri=make_absolute(reverse('auth-pipeline-end')), 
         state=state)) 


def end_pipeline(request): 
    if not constant_time_compare(request.session[SESSION_STATE], 
           request.GET['state']): 
     return redirect('home') 
    session = github.get_auth_session(data={'code': request.GET['code'], 
              'redirect_uri': 
              make_absolute(reverse('home'))}) 
    flush_and_set(request, SESSION_KEY, session.access_token) 
    user_data = session.get('https://api.github.com/user?' + 
          urllib.urlencode({'access_token': 
               session.access_token})).json() 
    username = user_data['login'] 
    try: 
     user = User.objects.get(username=username) 
    except User.DoesNotExist: 
     user = User(username=username) 
    for field in ('email',): 
     d = user_data[field] 
     if d: 
      setattr(user, field, d) 
    user.backend = 'mongoengine.django.auth.MongoEngineBackend' 
    user.save() 
    login(request, user) 
    return redirect('home') 

我有兩個問題:

  1. 是否安全,安全做到了這一點呢?
  2. 我應該在會話中設置過期嗎?因爲現在看來,它永遠不會到期。

注:我還使用rauth:https://rauth.readthedocs.org/en/latest/

回答

1

還不如安全,因爲它可以和一些細節缺乏。

    • 一個更加安全的狀態值使用SystemRandom
    • 您的會話是cookie based?他們不會被默認,他們不應該。
    • 重定向是否受HTTPS保護?
    • 您是否通過HTTPS向GitHub發送了所有請求?令牌獲得之後呢?
  1. 默認過期期限爲2周,但OAuth 2訪問令牌通常過期更快。不過我相信GitHub令牌永遠不會過期,因此改進將會在不再需要時關閉會話和delete the token

這就是說,我會強烈建議您使用python-social-auth不是滾動自己的GitHub登錄作爲該項目有它更多的眼睛,有一段時間。

+0

謝謝你的回答!所以不,會話不是基於cookie的(我得到他們應該是?)。我的網站不在HTTPS上,但是對Github的所有請求均採用HTTPS。我之前使用過django-social-auth,但遇到問題,我選擇了自己的解決方案(我只需要Github登錄)。也許我會再試一次。 – rubik

+0

他們不應該基於cookie,將編輯答案。此外,如果您的網站不在https上,則認證代碼可能會被嗅探並用於獲取訪問令牌,如果他們設法竊取/猜測您的客戶機密。 –

+0

當然,如果您不使用HTTPS,可以進行許多其他攻擊,所以如果您要使用OAuth 2,請使用HTTPS。 –