Веб-служба OAuth и Django-поршень

#django #web-services #api #oauth #django-piston

#django #веб-сервисы #API #oauth #django-поршень

Вопрос:

Я пытаюсь реализовать веб-службу с доступом к фильтруемым ресурсам (аутентификация OAuth) с помощью Django, и у меня возникла пара вопросов.

Я создал два веб-сервера:

Я пытаюсь использовать версию 1.0a OAuth для аутентификации потребителя перед поставщиком. Рабочий процесс этого протокола описан здесь.

В двух словах, вот различные шаги (название обмениваемого ресурса):

  1. Потребитель запрашивает токен у поставщика (ключ, секрет)
  2. Если потребитель действителен, поставщик возвращает ему токен (oauth_token, oauth_token_secret)
  3. Потребитель перенаправляет пользователя к поставщику для входа в систему / предоставления доступа (oauth_token)
  4. Пользователь предоставляет потребителю доступ к ресурсу.
  5. Поставщик предоставляет потребителю средство проверки токена (token_verifier)
  6. Потребитель запрашивает access_token (ключ, секрет, oauth_token, oauth_token_secret, oauth_verifier).
  7. Поставщик предоставляет потребителю доступ к токену (oauth_token)
  8. Потребитель использует свой oauth_token для доступа к ресурсу

Вот код представлений моего потребителя:

 from django.shortcuts import render_to_response
from django.http import HttpResponse, HttpResponseRedirect
import oauth2 as oauth
import urlparse

REQUEST_TOKEN_URL = 'http://127.0.0.1:8080/api/authentication/request_token/'
AUTHORIZATION_URL = 'http://127.0.0.1:8080/api/authentication/authorize/'
ACCESS_TOKEN_URL = 'http://127.0.0.1:8080/api/authentication/access_token/'
CONSUMER_CALLBACK_URL = 'http://127.0.0.1:8000/request_access_token/'

CONSUMER_KEY = 'key'
CONSUMER_SECRET = 'secret'

consumer = oauth.Consumer(CONSUMER_KEY, CONSUMER_SECRET)
client = oauth.Client(consumer)

def request_token(request):
    """
    Contacts the service provider to get a token.
    """ 
    resp, content = client.request(REQUEST_TOKEN_URL, 'GET')
    oauth_token = dict(urlparse.parse_qsl(content)).get('oauth_token', None)
    oauth_token_secret = dict(urlparse.parse_qsl(content)).get('oauth_token_secret',
                                                          None)

    if oauth_token is None:
        return render_to_response('home.html', {'data': 'NO TOKEN FOUND'})
    else:
        request.session['oauth_token'] = oauth_token
        request.session['oauth_token_secret'] = oauth_token_secret
        return HttpResponseRedirect('request_user_permission/')

def request_user_permission(request):
    """
    Redirects the user to the service provider to get permission if
    token provided.
    """
    oauth_token = request.session['oauth_token']

    if oauth_token is None:
        return render_to_response('home.html', {'data': 'NO TOKEN FOUND'})
    else:
        return HttpResponseRedirect("%s?oauth_token=%samp;oauth_callback=%s"
             % (AUTHORIZATION_URL, oauth_token, CONSUMER_CALLBACK_URL))


def request_access_token(request):
    """
    Requests an access token from the service provider
    if the user granted permission.
    """
    error = request.GET.get('error', None)

    if error is None:
        oauth_verifier = request.GET.get('oauth_verifier', None)

        if oauth_verifier is None:
            return render_to_response('home.html',
                                       {'data': 'UNKNOWN ERROR HAPPENED'})
        else:
            # User permission granted, requesting access token
            oauth_token = request.session['oauth_token']
            oauth_token_secret = request.session['oauth_token_secret']

            token = oauth.Token(oauth_token, oauth_token_secret)
            token.set_verifier(oauth_verifier)
            client.token = token

            resp, content = client.request(ACCESS_TOKEN_URL, 'POST')
            access_token = dict(urlparse.parse_qsl(content))
            return render_to_response('home.html', {'data': access_token})
    else:
        return render_to_response('home.html', {'data': error})
  

Общие вопросы по OAuth

  • Сколько токенов должно быть у потребителя? Один? По одному на пользователя? По одному на ресурс?
  • Как потребитель должен хранить свои токены?
  • Как вы указываете, к каким ресурсам пользователь может получить доступ с помощью своего токена? Разве потребитель не должен иметь возможность указывать идентификатор ресурса, к которому он хочет получить доступ, при перенаправлении пользователя поставщику услуг (шаг 3)?
  • Если потребитель хочет получить доступ к ресурсу, для которого пользователь уже предоставил доступ в прошлом, должен ли он в любом случае перенаправить пользователя поставщику услуг (и позволить поставщику услуг немедленно вернуть oauth_verifier, вместо того, чтобы запрашивать у пользователя разрешение)?

Технические проблемы

Прямо сейчас я использую сеансы кэширования локальной памяти для хранения токена, но это не работает:

  • Когда сеансы активируются на сервере-потребителе, Пользователь должен каждый раз входить в систему на сервере поставщика услуг (даже если он уже входил в систему).
  • В первом представлении (запрашивающий токен) Я сохраняю oauth_token и oauth_token_secret в сеансе запроса. Когда я пытаюсь получить к нему доступ во втором представлении (перед перенаправлением пользователя), это работает. Но когда я пытаюсь получить к нему доступ в последнем представлении (после перенаправления), это не так ( KeyError , oauth_token не найдено в request.session словаре)

Спасибо!

Ответ №1:

Я нахожусь в той же ситуации (внедряю API с аутентификацией OAuth), и в ходе своих исследований я наткнулся на проект django-oauth-plus. В руководстве проделана хорошая работа по прохождению каждого шага процесса, описанного на схеме, на которую вы ссылаетесь. Сам код кажется довольно полной реализацией OAuth (не уверен, знаю ли я, о чем говорю, просто изучаю этот материал).

Кроме того, у этого парня есть довольно отличный учебник по основам OAuth (я боролся с этим).