零基础入门python22:注册接口与密码哈希——为什么不能保存明文密码

发布时间:2026/10/27 2:34:32

零基础入门python22:注册接口与密码哈希——为什么不能保存明文密码 零基础入门python22注册接口与密码哈希——为什么不能保存明文密码一、上一篇课后练习讲解给账目增加日期时使用date类型并让数据库列建立索引测试应创建两天数据查询某一天只返回对应记录。日期过滤要使用范围或等值比较不要把日期转换成字符串再模糊搜索。上一篇课后练习完整答案上一篇练习的要求已落实到下面完整文件先运行项目测试再用 curl 对照状态码和数据库持久化结果答案要点User、Category、Entry 用外键和联合唯一约束表达所有权金额 Numeric、用户 id 索引以及可空分类都在模型中落地。文件app/models.py完整参考答案文件完整文件app/models.pyfrom.extensionsimportdbclassUser(db.Model):__tablename__usersiddb.Column(db.Integer,primary_keyTrue)emaildb.Column(db.String(254),uniqueTrue,nullableFalse)classCategory(db.Model):__tablename__categories__table_args__(db.UniqueConstraint(user_id,name),)iddb.Column(db.Integer,primary_keyTrue)user_iddb.Column(db.ForeignKey(users.id),nullableFalse)namedb.Column(db.String(30),nullableFalse)classEntry(db.Model):__tablename__entriesiddb.Column(db.Integer,primary_keyTrue)user_iddb.Column(db.ForeignKey(users.id),nullableFalse)amountdb.Column(db.Numeric(12,2),nullableFalse)kinddb.Column(db.String(10),nullableFalse)完整参考答案文件本篇对应的交付源码完整文件flask-ledger/app/models.pyfromdatetimeimportdate,datetime,timezonefromdecimalimportDecimalfromflask_loginimportUserMixinfromwerkzeug.securityimportcheck_password_hash,generate_password_hashfrom.extensionsimportdb,login_managerclassUser(UserMixin,db.Model):iddb.Column(db.Integer,primary_keyTrue)emaildb.Column(db.String(120),uniqueTrue,nullableFalse,indexTrue)password_hashdb.Column(db.String(255),nullableFalse)created_atdb.Column(db.DateTime,defaultlambda:datetime.now(timezone.utc))defset_password(self,password:str)-None:self.password_hashgenerate_password_hash(password)defcheck_password(self,password:str)-bool:returncheck_password_hash(self.password_hash,password)login_manager.user_loaderdefload_user(user_id:str):returndb.session.get(User,int(user_id))classCategory(db.Model):__table_args__(db.UniqueConstraint(user_id,name),)iddb.Column(db.Integer,primary_keyTrue)namedb.Column(db.String(40),nullableFalse)user_iddb.Column(db.Integer,db.ForeignKey(user.id),nullableFalse,indexTrue)classTransaction(db.Model):iddb.Column(db.Integer,primary_keyTrue)kinddb.Column(db.String(10),nullableFalse)amountdb.Column(db.Numeric(12,2),nullableFalse)notedb.Column(db.String(200),default)happened_ondb.Column(db.Date,defaultdate.today,nullableFalse,indexTrue)user_iddb.Column(db.Integer,db.ForeignKey(user.id),nullableFalse,indexTrue)category_iddb.Column(db.Integer,db.ForeignKey(category.id),nullableFalse)defto_dict(self)-dict:return{id:self.id,kind:self.kind,amount:str(Decimal(self.amount).quantize(Decimal(0.01))),note:self.note,happened_on:self.happened_on.isoformat(),category_id:self.category_id,}验收命令python -m pytest -qDjango 项目使用 python manage.py test。预期测试通过若失败先检查迁移、配置和事务回滚。二、本篇完成什么实现注册接口规范化邮箱、校验密码、检查重复用户、使用 Werkzeug 哈希、提交数据库并返回用户 id。三、关键代码fromwerkzeug.securityimportgenerate_password_hashdefset_password(self,password:str)-None:只保存哈希不保存原密码哈希算法和盐由 Werkzeug 管理。self.password_hashgenerate_password_hash(password)注册接口先检查输入再查询数据库最后提交。密码不能出现在响应、日志或异常信息中重复邮箱返回 409表示资源冲突而不是服务器错误。四、运行结果curl-X POST http://127.0.0.1:5000/api/auth/register-HContent-Type: application/json-d{\email\:\aliceexample.com\,\password\:\secret123\}首次返回 201再次提交相同邮箱返回 409短密码返回 400。验收还要查询数据库确认password_hash不是secret123。课后练习增加邮箱大小写归一化测试。项目增量注册事务和密码哈希注册先规范化邮箱再使用 Werkzeug 哈希密码数据库 UNIQUE 处理并发重复IntegrityError 后必须 rollback。userUser(emailemail.strip().casefold())user.set_password(password)db.session.add(user)try:db.session.commit()exceptIntegrityError:db.session.rollback()raiseEmailAlreadyUsed()验收成功 201、重复邮箱 409、密码列不是明文。课后练习写两个 Session 的重复注册测试。五、注册流程为什么要分成“校验—哈希—提交”注册接口接收的是不可信输入。正确顺序是先做格式和长度校验再生成密码哈希最后在一个事务中写入用户。不能先INSERT再校验否则异常回滚会让日志和错误响应变得混乱也不能把密码原文临时写入日志。fromflaskimportrequestfromwerkzeug.securityimportgenerate_password_hashfromsqlalchemy.excimportIntegrityErrorauth_bp.post(/register)defregister():bodyrequest.get_json(silentTrue)or{}emailbody.get(email,).strip().lower()passwordbody.get(password,)ifnotinemailorlen(email)254:return{error:email_invalid},400iflen(password)8:return{error:password_too_short},400userUser(emailemail,password_hashgenerate_password_hash(password))db.session.add(user)try:db.session.commit()exceptIntegrityError:db.session.rollback()return{error:email_exists},409return{id:user.id,email:user.email},201这里的lower()是为了统一邮箱大小写但不要擅自去掉邮箱中的tag具体规则应该在产品需求里确定。generate_password_hash默认使用带盐算法即使两个用户密码相同哈希结果也不同。数据库唯一约束是最后一道防线因为并发请求可能同时通过“先查询是否存在”的检查。六、用 curl 观察真实 HTTP 行为curl-Method Post http://127.0.0.1:5000/api/auth/register -ContentTypeapplication/json-Body{email:aliceexample.com,password:correct-horse}首次请求返回201和用户 id再次发送同样请求应返回409。把密码改成123应返回400而不是数据库错误。若返回415 Unsupported Media Type是因为缺少Content-Type: application/json若request.get_json()得到None先查看请求体是否是合法 JSON。七、密码验证和时间成本登录时使用check_password_hash(user.password_hash, supplied_password)不要自行比较哈希字符串。哈希算法故意较慢用来增加撞库成本因此注册接口应设置速率限制且不要在一个请求里重复计算多次。生产环境还应记录失败次数和 IP但日志只记录邮箱的掩码形式如a***example.com。八、上一篇练习的验收上一篇要求两个 Session 并发重复注册。测试可使用两个独立客户端同时发送请求预期一条 201、一条 409数据库最终只有一条用户记录如果两条都 201说明数据库唯一约束没有迁移到当前环境。九、本篇练习增加username字段要求 3—30 个字且唯一为注册接口补充邮箱格式、密码过短、重复邮箱三个 pytest在响应中加入created_at的 ISO 8601 字符串但不要暴露password_hash。下一篇将把注册成功的用户放进会话解释 cookie、session 和退出登录的差别。十、把错误变成稳定的接口契约建议统一返回{error: email_exists, message: 邮箱已注册}状态码表达类别error供前端判断message供人阅读。测试不要断言完整中文句子而应断言error和状态码。生产日志记录request_id、邮箱掩码和异常类型绝不记录密码。这样既方便排障也不会因为换文案而破坏客户端。注册成功后可以发送欢迎邮件但邮件服务属于外部依赖不应该包在创建用户的数据库事务里正确做法是先提交用户再投递异步任务失败时记录待重试状态。本篇的事务边界只覆盖用户记录后续订单事务会复用同样原则。本篇结束完整模块文件下面是交付项目中真实存在的完整文件 flask-ledger/app/auth.py。它覆盖本篇新增逻辑以及前文已经完成的依赖代码复制单个函数会丢失上下文因此这里提供整份文件。fromflaskimportBlueprint,requestfromflask_loginimportcurrent_user,login_required,login_user,logout_userfrom.extensionsimportdbfrom.modelsimportUser bpBlueprint(auth,__name__,url_prefix/api/auth)bp.post(/register)defregister():datarequest.get_json(silentTrue)or{}emailstr(data.get(email,)).strip().lower()passwordstr(data.get(password,))ifnotinemail:return{message:邮箱格式不正确},400iflen(password)8:return{message:密码至少8位},400ifdb.session.scalar(db.select(User).where(User.emailemail)):return{message:邮箱已注册},409userUser(emailemail)user.set_password(password)db.session.add(user)db.session.commit()return{id:user.id,email:user.email},201bp.post(/login)deflogin():datarequest.get_json(silentTrue)or{}emailstr(data.get(email,)).strip().lower()userdb.session.scalar(db.select(User).where(User.emailemail))ifnotuserornotuser.check_password(str(data.get(password,))):return{message:邮箱或密码错误},401login_user(user)return{id:user.id,email:user.email}bp.post(/logout)login_requireddeflogout():logout_user()return{message:已退出}bp.get(/me)login_requireddefme():return{id:current_user.id,email:current_user.email}
延伸阅读

更多相关文章

2026/10/21 0:18:51

MoneyPrinterTurbo 视频生成效果实测与能力边界深度解析

随着AIGC技术的飞速发展,自动化视频生成工具逐渐成为内容创作者的“效率外挂”。本文将对近期备受关注的 MoneyPrinterTurbo​ 项目进行全方位的实测与评测。我们将从核心架构、多风格文案转视频、AI配音、素材匹配、画质输出、典型场景案例以及系统性能等多个维度展…

2026/10/27 2:32:38

GraphRAG与传统RAG技术对比与应用解析

1. GraphRAG与传统RAG的技术对比全景图在知识增强生成领域,GraphRAG和传统RAG代表着两种截然不同的技术路线。传统RAG(Retrieval-Augmented Generation)通过向量相似度检索文档片段来增强大语言模型的生成能力,而GraphRAG则创新性…

2026/10/27 2:32:38

Markmap工具全解析:从原理到企业级应用

1. Markmap-tool-service工具初探:思维导图开发者的瑞士军刀第一次接触Markmap-tool-service是在去年重构技术文档时,当时需要将复杂的系统架构用可视化方式呈现。这个基于Markdown的思维导图工具,通过简单的语法就能生成交互式脑图&#xff…

2026/10/27 2:32:38

计算机博弈竞赛核心:棋类参数、博弈树剪枝与评估函数

简介:《计算机博弈竞赛辅导资料》是一份面向计算机博弈竞赛参赛者及人工智能博弈方向学习者的PPT讲义,侧重帮助读者建立从棋类对象、软件架构到搜索与评估的知识框架。压缩包内含1个PPT文件,大小约2.57MB,内容以课堂讲义形式组织&…

2026/10/27 2:32:38

OpenClaw:结构化数据处理与量化分析开源工具

1. OpenClaw项目概述OpenClaw是一个专注于结构化数据处理、趋势分析和指标量化的开源工具集。这个名字让我联想到小龙虾(crawfish)的双钳——就像它的名字一样,这个工具能够精准抓取、处理和分析各类结构化数据。从GitHub上的项目热度来看&am…

2026/10/27 2:32:38

深入解析计算机内存管理:原理、技术与实践

1. 内存管理的基本概念与重要性内存管理是计算机系统中最为核心的基础功能之一。简单来说,它就是操作系统如何高效、合理地分配和使用计算机内存资源的过程。想象一下内存就像是一个大型仓库,而内存管理就是这个仓库的管理员,负责决定哪些货物…

2026/10/27 2:27:38

2026最新版Maven安装与配置优化全指南

1. 2026最新版Maven安装全流程指南作为Java生态中经久不衰的构建工具,Maven在2026年依然保持着强大的生命力。最近在帮团队统一开发环境时,我发现网上很多教程还停留在老版本,有些配置项已经不再适用。这里分享下经过实际验证的最新安装方案&…

2026/10/26 0:20:20

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/26 1:53:47

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/27 0:59:21

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式19_“模式选错”的典型代价

“模式选错”的典型代价 摘要 在软件工程中,设计模式、架构模式、并发模式乃至团队协作模式的选择,往往在项目早期就决定了后续的开发效率和维护成本。本文通过多个真实场景,剖析“模式选错”带来的典型代价——包括返工成本、技术债务累积、…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式20_新手推荐路径

新手推荐路径 摘要 在 AI 辅助开发工具快速普及的今天,新手面对最多的困惑往往不是"工具够不够强",而是"我该从哪一步开始用"。本文提出一条经过实践验证的三阶段学习路径:先从 Ask(问答式交互)起…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑