#django #web-services #api #oauth #django-piston
#django #веб-сервисы #API #oauth #django-поршень
Вопрос:
Я пытаюсь реализовать веб-службу с доступом к фильтруемым ресурсам (аутентификация OAuth) с помощью Django, и у меня возникла пара вопросов.
Я создал два веб-сервера:
- http://localhost:8080 : Поставщик веб-услуг (использующий django-piston для веб-сервиса)
- http://localhost:8000 : Потребитель веб-сервиса
Я пытаюсь использовать версию 1.0a OAuth для аутентификации потребителя перед поставщиком. Рабочий процесс этого протокола описан здесь.
В двух словах, вот различные шаги (название обмениваемого ресурса):
- Потребитель запрашивает токен у поставщика (ключ, секрет)
- Если потребитель действителен, поставщик возвращает ему токен (oauth_token, oauth_token_secret)
- Потребитель перенаправляет пользователя к поставщику для входа в систему / предоставления доступа (oauth_token)
- Пользователь предоставляет потребителю доступ к ресурсу.
- Поставщик предоставляет потребителю средство проверки токена (token_verifier)
- Потребитель запрашивает access_token (ключ, секрет, oauth_token, oauth_token_secret, oauth_verifier).
- Поставщик предоставляет потребителю доступ к токену (oauth_token)
- Потребитель использует свой 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 (я боролся с этим).