【Python项目实战】用户系统:注册登录与密码哈希

【Python项目实战】用户系统:注册登录与密码哈希 现在你的博客有个大漏洞:任何人都能发文章、删文章。今天装上门禁——注册、登录、登出,顺便回答【Python项目实战】项目·强密码生成器:随机、安全与剪贴板这篇文章里埋的那个问题:为什么密码必须“哈希加盐”存储。🎯本篇成品:博客v3——注册、登录、登出、flash提示、登录门禁(没登录不能写/删)。零新增依赖:密码哈希用的werkzeug随Flask自带。含注释约130行。📌 太长不看版(给想快速上手的你)项目信息一句话说明项目名称Flask博客(v3·用户系统版)代码行数~130行(含注释) + 模板文件依赖零新增!werkzeug随Flask自带核心功能注册 + 登录 + 登出 + 登录门禁 + flash提示跑起来的命令python main.py→ 浏览器打开http://127.0.0.1:5000核心知识点密码哈希加盐、session会话、自定义装饰器做完你能得到一个有门禁的博客,从“玩具”变“产品”!一、密码为什么不能明文存(第9篇伏笔兑现)假设数据库泄露了(忘改debug、弱密码后台、云盘误分享……),两种结局:存储方式攻击者看到的后果❌明文存密码打开表,所有账号当场沦陷大多数人到处复用密码,沦陷会蔓延到邮箱、支付账号✅哈希存一串$scrypt$32768$8$1$...的天书没有密码原文,登录不了🔪 哈希函数是单向的碎纸机📌把密码绞成指纹容易,从指纹还原密码(目前)不可能。登录时做的不是“解密密码”,而是把你输入的密码重新绞一遍,比对两坨指纹是否一致。🧂 “加盐”是什么?问题加盐的解法如果两个用户密码相同,哈希值也相同盐 = 给每个密码撒一把随机字符再哈希攻击者提前算好“常见密码→哈希”对照表(彩虹表),按表查就破解了让相同的密码生出不同的哈希,彩虹表直接作废🧪 亲手验证💡secrets是“必须不可预测”,werkzeug的盐是“故意每次不同”——方向相反的一对。fromwerkzeug.securityimportgenerate_password_hashgenerate_password_hash("python666")'scrypt:32768:8:1$saltA$...'generate_password_hash("python666")'scrypt:32768:8:1$saltB$...'# 同一个密码,两个完全不同的哈希✅好消息:这两个函数在werkzeug.security里,Flask自带werkzeug——本篇零新增依赖。二、第二个概念:session——HTTP的“记忆手环”HTTP是无状态的:每个请求都是陌生人,上一秒登录、下一秒服务器就把你忘了。session就是解决方案:登录成功后服务器发你一个“签名手环”(Cookie),之后每个请求亮手环,Flask验签后知道“你是谁”。概念比喻说明session["uid"] = 用户id手环内容由Flask用SECRET_KEY签名,篡改内容签名就对不上,手环自动作废SECRET_KEY手环的防伪印刷术泄露它,任何人都能伪造登录三、第0步:setup1. 复制flask_blog_v2为flask_blog_v3(保留v2) 2. 激活venv 3. 无需安装任何新包(werkzeug随Flask自带) 4. git commit一次干净的起点四、第1步:SECRET_KEY——手环的防伪印刷术importos app=Flask(__name__)app.config["SQLALCHEMY_DATABASE_URI"]="sqlite:///blog.db"app.config["SQLALCHEMY_TRACK_MODIFICATIONS"]=False# 生产环境:从环境变量读(第5篇军规——密钥不进仓库)app.config["SECRET_KEY"]=os.environ.get("BLOG_SECRET_KEY","dev-only-do-not-use-in-prod")⚠️ 两个注意点#注意点说明①没有SECRET_KEY就用sessionFlask会当场报错(第十节①)②SECRET_KEY必须固定每次启动随机生成的话,重启一次全体用户被“踢下线”(第十节③)五、第2步:User模型——存指纹,不存密码fromwerkzeug.securityimportgenerate_password_hash,check_password_hashclassUser(db.Model):__tablename__="users"id=db.Column(db.Integer,primary_key=True)username=db.Column(db.String(40),unique=True,nullable=False)password_hash=db.Column