microdot.login --- 用户登录流程¶
围绕 microdot.session 的更高层封装,实现了常规的用户名/密码登录流程:用户加载器 回调将会话中存储的用户 id 映射回应用程序的用户对象,路由装饰器将未经身份验证的请求重定向到可配置的登录 URL,可选的“记住我”cookie 让回访用户跨浏览器会话保持登录状态。
要求在构造登录对象 之前 已在应用程序上初始化 microdot.session——会话正是存储用户 id 的地方。
class Login¶
- class microdot.login.Login(login_url: str = '/login')¶
- login_url
装饰器将未经身份验证的请求重定向到的 URL。应用程序在此路由上提供实际的登录表单/处理程序。默认为
'/login'。
- user_loader(f)¶
用于注册用户解析回调的装饰器。f 接收存储在会话中的用户 id,并返回用户对象(如果该 id 不再有效——账户已删除、会话已撤销等——则返回
None)。login = Login() @login.user_loader async def load_user(user_id): return users.get(user_id)
- __call__(f)¶
用
Login实例装饰一个路由即可将其置于身份验证保护之后:@app.get('/dashboard') @login async def dashboard(request): user = request.g.current_user # ...
未经身份验证的请求会被重定向到 login_url,并带有
?next=<original-url>查询参数,以便登录处理程序能将用户送回其原先所在之处。
- fresh(f)¶
与
__call__()类似,但拒绝从“记住我”cookie 恢复的会话——用户必须在上次完整登录之后显式重新登录过。用于保护敏感路由(修改密码、删除账户),使被盗的记住我 cookie 无法访问它们。
- async login_user(request, user, remember: bool | int = False, redirect_url: str = '/')¶
将 user 标记为已为 request 登录。在会话中存储用户 id 并返回一个重定向响应。
- user
用户加载器返回的用户对象。必须具有
id属性。- remember
如果为真值,则还会设置一个长期有效的
_remembercookie。传入True表示默认的 30 天,或传入一个整数表示 cookie 应持续的天数。- redirect_url
登录后重定向到何处。如果原始请求中的
?next=<url>指向同站路径,则会被其覆盖。
返回重定向响应——从登录路由处理程序中返回其值。
- async logout_user(request)¶
从会话中清除用户 id 并移除任何
_remembercookie。在/logout路由中使用:@app.post('/logout') async def logout(request): await login.logout_user(request) return redirect('/')
- async get_current_user(request)¶
返回当前已登录的用户对象(或
None)。会在request.g.current_user上进行记忆化,因此同一请求内的重复调用只会命中加载器一次。
示例¶
一个最小化的登录流程:
from microdot import Microdot, redirect
from microdot.session import Session
from microdot.login import Login
app = Microdot()
Session(app, secret_key=load_secret())
login = Login()
@login.user_loader
async def load_user(user_id):
return users.get(user_id)
@app.get('/login')
async def login_page(request):
return Response.send_file('static/login.html')
@app.post('/login')
async def do_login(request):
user = authenticate(request.form['user'], request.form['pass'])
if not user:
return redirect('/login?error=1')
return await login.login_user(request, user, remember=True)
@app.get('/dashboard')
@login
async def dashboard(request):
return 'hi ' + request.g.current_user.name
@app.post('/logout')
async def logout(request):
await login.logout_user(request)
return redirect('/')
_remember cookie 本身是一个签名的 JWT(使用会话的密钥),因此被盗的 cookie 无法在不同的应用程序上重用,也无法在密钥轮换之后重用。