Форум сайта python.su
В туториалах 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,
)
Офлайн
Добавьте в view_config custom_predicate, который сработает на authenticated_userid(request) и вернет renderer с красивой картинкой для 403 Forbidden
Офлайн
Спасибо Андрей! Родился такой вариант, избавленный от некрасивых 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,
)
Офлайн
Гуглил на тему 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,
)
Офлайн
Мне отчего-то казалось, что вы о render_to_response и так знали, да не хотели использовать.
О скорости не беспокойтесь — оно всё примерно одинаковое
Офлайн
Нет, не знал, я еще начинающий пирамидовод.
А так - да, причины не использовать render_to_response действительно могут быть - решение выглядит как хак, т.е. вначале указывается один рендерер, а внутри используется другой. Нарушается “стройность” декораторов )
Офлайн