Как мне обработать выходы с помощью repoze.who (и bottle.py)?

Я пытаюсь заставить bottle.py работать с repoze.who, и до сих пор удалось собрать следующую очень упрощенную программу, чтобы она работала, используя комбинацию различных примеров, которые я нашел. Очевидно, что это не то, что я запускаю в производственном процессе, я просто пытаюсь сделать как можно менее сложный код, чтобы я мог научиться его использовать - но, к сожалению, руководства по использованию bottle.py с repoze.who очень мало и далеко друг от друга.

Этот пример ниже работает, и позволяет кому-то войти в систему с именем пользователя / паролем администратора / администратора. Что я должен делать с repoze.who, чтобы заставить работать функцию logout()? Я понимаю, что для этой цели может быть предусмотрена функция забытия, но я не могу понять, как мне это называть.

Благодарю.

from bottle import route, run, app, get, abort, request

from StringIO import StringIO
import repoze
from repoze.who.middleware import PluggableAuthenticationMiddleware
from repoze.who.interfaces import IIdentifier
from repoze.who.interfaces import IChallenger
from repoze.who.plugins.basicauth import BasicAuthPlugin
from repoze.who.plugins.auth_tkt import AuthTktCookiePlugin
from repoze.who.plugins.cookie import InsecureCookiePlugin
from repoze.who.plugins.form import FormPlugin
from repoze.who.plugins.htpasswd import HTPasswdPlugin
from repoze.who.classifiers import default_request_classifier
from repoze.who.classifiers import default_challenge_decider    

import logging, sys
import pprint

@route('/')
def root():
    if request.environ.get('repoze.who.identity') is None:
        abort(401, "Not authenticated")
    return "Authenticated"


@route('/hello')
def index():
    identity = request.environ.get('repoze.who.identity')
    if identity == None:
        abort(401, "Not authenticated")

    user = identity.get('repoze.who.userid')
    return '<b>Hello %s!</b>' % user

@route('/logout')
def logout():
    # I have no idea what to put here
    pass

io = StringIO()
salt = 'aa'

for name, password in [ ('admin', 'admin'), ('paul', 'paul') ]:
    io.write('%s:%s\n' % (name, password))
io.seek(0)

def cleartext_check(password, hashed):
    return password == hashed

htpasswd = HTPasswdPlugin(io, cleartext_check)
basicauth = BasicAuthPlugin('repoze.who')
auth_tkt = AuthTktCookiePlugin('secret', 'auth_tkt')
form = FormPlugin('__do_login', rememberer_name='auth_tkt')
form.classifications = { IIdentifier:['browser'],
                         IChallenger:['browser'] }
identifiers = [('form', form),('auth_tkt',auth_tkt),('basicauth',basicauth)]
authenticators = [('htpasswd', htpasswd)]
challengers = [('form',form), ('basicauth',basicauth)]
mdproviders = []


log_stream = None
import os
if os.environ.get('WHO_LOG'):
    log_stream = sys.stdout

middleware = PluggableAuthenticationMiddleware(
    app(),
    identifiers,
    authenticators,
    challengers,
    mdproviders,
    default_request_classifier,
    default_challenge_decider,

    log_stream = log_stream,
    log_level = logging.DEBUG
    )

if __name__ == '__main__':
    run(app=middleware, host='0.0.0.0', port=8080, reloader=True)
else:
    application = middleware

run(host='0.0.0.0', port=8080)

2 ответа

Решение

Если бы ты мог, я бы использовал RedirectingFormPlugin скорее, чем FormPlugin, RedirectingFormPlugin позволяет зарегистрировать URL выхода из системы. С ним вам не нужно реализовывать /logout обработчик как таковой RedirectingFormPlugin перехватывает запрос и обрабатывает звонки, чтобы забыть и т.д. для вас. Я использовал это с Бобо и Appengine, и это работает хорошо.

Если вы все еще хотите сделать это в старом repoze.who v1, то у меня сработало следующее:

from bottle import response # , redirect
# ...
@route('/logout')
def logout():
    identity = request.environ.get('repoze.who.identity')
    if identity:
        for (i_name, i) in identifiers:
            hdrs = i.forget(request.environ, identity)
            [ response.add_header(*h) for h in hdrs ]
    ## following would be nice, but does not work,
    ## since redirect is not using defined response headers
    # rfr = request.get_header('referer', '/')
    # redirect(rfr)
    ## so we do just this:
    return "you have been hopefully logged out"
Другие вопросы по тегам