- 在使用bottle.py和repoze.who进行用户身份验证时,需要实现用户登出功能。但原有的代码中没有针对登出操作的处理,需要补充实现。
2、解决方案 可以使用repoze.who提供的forget函数来实现登出功能。forget函数的作用是清除用户认证信息,本质上是删除了存储在浏览器cookie中的认证令牌。具体实现步骤如下:
- 在bottle.py的路由函数中,添加登出路由。例如:
@route('/logout')
def logout():
# 调用forget函数清除认证信息
repoze.who.forget(request.environ)
# 返回登出成功信息
return "登出成功"
- 在repoze.who的配置中,添加InsecureCookiePlugin插件。InsecureCookiePlugin插件用于管理用户认证令牌的存储。
import repoze.who.plugins.cookie as cookie
# 添加InsecureCookiePlugin插件
cookie_plugin = cookie.InsecureCookiePlugin()
- 将InsecureCookiePlugin插件添加到repoze.who的认证中间件中。
from repoze.who.middleware import PluggableAuthenticationMiddleware
# 添加认证中间件
middleware = PluggableAuthenticationMiddleware(
app(), # your application
# 其他的配置项
cookie_plugins=(cookie_plugin,), # 添加InsecureCookiePlugin插件
)
这样,当用户访问/logout路由时,forget函数将被调用,清除用户的认证信息,实现用户登出。用户登出后,再次访问需要认证的页面时,将被要求重新登录。
代码例子:
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, RedirectingFormPlugin
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():
# 调用forget函数清除认证信息
repoze.who.forget(request.environ)
# 返回登出成功信息
return "登出成功"
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')
# 使用RedirectingFormPlugin处理表单认证
form = RedirectingFormPlugin('__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
# 添加InsecureCookiePlugin插件
cookie_plugin = InsecureCookiePlugin()
middleware = PluggableAuthenticationMiddleware(
app(),
identifiers,
authenticators,
challengers,
mdproviders,
default_request_classifier,
default_challenge_decider,
log_stream = log_stream,
log_level = logging.DEBUG,
cookie_plugins=(cookie_plugin,) # 添加InsecureCookiePlugin插件
)
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)