登录失败多少次该锁?怎么锁才不会被人拿来封号?响应和时间会不会泄漏账号是否存在?并发请求能不能绕过计数?这篇在真实的 PostgreSQL 上把这些细节逐个验证(只验证防护这一端)。
连续 5 次错误密码: [401, 401, 401, 401, 401]
锁定期间用正确的密码 → 401 {'error': 'invalid credentials or account temporarily locked'}
2 秒后用正确的密码 → 200 {'ok': True}
成功之后库里的失败计数: 0
bob 失败 2 次后成功登录一次,计数: 0 (中途成功会清零)上一篇:密码哈希与密码升级;下一篇:开发模式 Debugger 风险。
第 129 篇讲过用 Flask-Limiter 限流,这一篇讲应用层的账号锁定。
朴素:不存在 404 / 密码错 401,消息不同
不存在的用户 → 404 {'error': 'user not found'}
存在的用户、错误密码 → 401 {'error': 'wrong password'}
统一:都是 401 与同一句话
不存在的用户 → 401 {'error': 'invalid credentials or account temporarily locked'}
存在的用户、错误密码 → 401 {'error': 'invalid credentials or account temporarily locked'}朴素 不存在的用户 0.6 ms | 存在的用户(错误密码) 66.3 ms | 差 65.7 ms 统一(不存在的用户也算哈希) 不存在的用户 66.1 ms | 存在的用户(错误密码) 66.4 ms | 差 0.3 ms
读出再写回(非原子) 真正去校验了密码的尝试 20 次(上限 5),被拒绝 0 次 原子 UPDATE ... WHERE fails < 上限 真正去校验了密码的尝试 5 次(上限 5),被拒绝 15 次
并发用 20 个线程同时发请求(各自的 test client 与数据库连接),数据库是自己起的 PostgreSQL。