Уведомления

Группа в Telegram: @pythonsu

#1 Авг. 30, 2011 04:21:56

Solaris
От:
Зарегистрирован: 2011-06-02
Сообщения: 18
Репутация: +  0  -
Профиль   Отправить e-mail  

Pyramid - правильная логин-форма и ошибка 403

В туториалах Pyramid есть wiki приложение (то, которое с traversal). В нем реализована прозрачная авторизация, т.е. когда пользователь не имеет прав, ему показывается логин-форма. При этом если пользователь уже залогинен, но не имеет прав, ему все равно показывается форма логина. Для нормального сайта такая ситуация неприемлима. Если пользователь уже залогинен - ему нужно показать ошибку 403.

Мое решение следующее:

from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember
from pyramid.security import forget
from pyramid.view import view_config

from test.security import USERS
from pyramid.security import authenticated_userid

@view_config(context='pyramid.httpexceptions.HTTPForbidden',
renderer='test:templates/forbidden.pt')
def forbidden(request):
logged_in = authenticated_userid(request)

if not logged_in:
new_url = request.application_url + '/login?came_from=' + request.url
return HTTPFound(location = new_url)

return dict(
)

@view_config(context='test.models.MyApp', name='login',
renderer='test:templates/login.pt')
def login(request):
login_url = request.resource_url(request.context, 'login')

referrer = request.url
if referrer == login_url:
referrer = '/' # never use the login form itself as came_from
came_from = request.params.get('came_from', referrer)
message = ''
login = ''
password = ''
if 'form.submitted' in request.params:
login = request.params['login']
password = request.params['password']
if USERS.get(login) == password:
headers = remember(request, login)
return HTTPFound(location = came_from,
headers = headers)
message = 'Failed login'

return dict(
message = message,
url = request.application_url + '/login',
came_from = came_from,
login = login,
password = password,
)
В этом решении меня все устраивает, но не очень нравится передача came_from через GET от вида forbidden в логин форму (мозолит глаза в строке запроса).

Может уважаемые гуру подскажут еще вариантов?



Офлайн

#2 Авг. 30, 2011 17:53:31

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Pyramid - правильная логин-форма и ошибка 403

Добавьте в view_config custom_predicate, который сработает на authenticated_userid(request) и вернет renderer с красивой картинкой для 403 Forbidden



Офлайн

#3 Авг. 31, 2011 00:58:35

Solaris
От:
Зарегистрирован: 2011-06-02
Сообщения: 18
Репутация: +  0  -
Профиль   Отправить e-mail  

Pyramid - правильная логин-форма и ошибка 403

Спасибо Андрей! Родился такой вариант, избавленный от некрасивых url:

from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember
from pyramid.security import forget
from pyramid.view import view_config
from pyramid.i18n import TranslationStringFactory

from test.security import USERS
from pyramid.security import authenticated_userid

def user_logged_predicate(logged):
def user_logged(context, request):
return (authenticated_userid(request)!=None) == logged
return user_logged

@view_config(context='pyramid.httpexceptions.HTTPForbidden',
renderer='test:templates/forbidden.pt',
custom_predicates=(user_logged_predicate(True),))
def forbidden(request):
return dict(
)

@view_config(context='pyramid.httpexceptions.HTTPForbidden',
renderer='test:templates/login.pt',
custom_predicates=(user_logged_predicate(False),))
@view_config(context='test.models.MyApp', name='login',
renderer='test:templates/login.pt')
def login(request):
login_url = request.resource_url(request.context, 'login')

referrer = request.url
if referrer == login_url:
referrer = '/' # never use the login form itself as came_from
came_from = request.params.get('came_from', referrer)
message = ''
login = ''
password = ''
if 'form.submitted' in request.params:
login = request.params['login']
password = request.params['password']
if USERS.get(login) == password:
headers = remember(request, login)
return HTTPFound(location = came_from,
headers = headers)
message = 'Failed login'

return dict(
message = message,
url = request.application_url + '/login',
came_from = came_from,
login = login,
password = password,
)



Офлайн

#4 Авг. 31, 2011 01:14:29

Solaris
От:
Зарегистрирован: 2011-06-02
Сообщения: 18
Репутация: +  0  -
Профиль   Отправить e-mail  

Pyramid - правильная логин-форма и ошибка 403

Гуглил на тему custom_predicates и наткнулся на интересную ссылку:
http://stackoverflow.com/questions/6553569/in-pyramid-how-can-i-use-a-different-renderer-based-on-contents-of-context

Почерпнул оттуда еще один вариант реализации с помощью render_to_response (возможно самый лаконичный и быстрый из всех)

from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember
from pyramid.security import forget
from pyramid.view import view_config
from pyramid.i18n import TranslationStringFactory
from pyramid.renderers import render_to_response

from test.security import USERS
from pyramid.security import authenticated_userid

@view_config(context='pyramid.httpexceptions.HTTPForbidden',
renderer='test:templates/login.pt')
@view_config(context='test.models.MyApp', name='login',
renderer='test:templates/login.pt')
def login(request):
opts = dict(page=request.context)
if authenticated_userid(request):
return render_to_response('test:templates/forbidden.pt',
opts, request)

login_url = request.resource_url(request.context, 'login')

referrer = request.url
if referrer == login_url:
referrer = '/' # never use the login form itself as came_from
came_from = request.params.get('came_from', referrer)
message = ''
login = ''
password = ''
if 'form.submitted' in request.params:
login = request.params['login']
password = request.params['password']
if USERS.get(login) == password:
headers = remember(request, login)
return HTTPFound(location = came_from,
headers = headers)
message = 'Failed login'

return dict(
message = message,
url = request.application_url + '/login',
came_from = came_from,
login = login,
password = password,
)



Офлайн

#5 Авг. 31, 2011 08:33:56

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Pyramid - правильная логин-форма и ошибка 403

Мне отчего-то казалось, что вы о render_to_response и так знали, да не хотели использовать.
О скорости не беспокойтесь — оно всё примерно одинаковое



Офлайн

#6 Авг. 31, 2011 12:28:25

Solaris
От:
Зарегистрирован: 2011-06-02
Сообщения: 18
Репутация: +  0  -
Профиль   Отправить e-mail  

Pyramid - правильная логин-форма и ошибка 403

Нет, не знал, я еще начинающий пирамидовод.

А так - да, причины не использовать render_to_response действительно могут быть - решение выглядит как хак, т.е. вначале указывается один рендерер, а внутри используется другой. Нарушается “стройность” декораторов )



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version