← 返回教程库

用户系统:登录注册 / 鉴权 / 权限的省力做法

最后更新 2026-06-22
你将学到
  • 知道用户系统别从零造轮子,用托管鉴权或社交登录最省力
  • 看懂「注册 → 登录 → 受保护接口校验」的最小流程,理解会话和 JWT 怎么选
  • 牢记密码永远 hash+salt 不存明文,权限按最小够用原则给
  • 用一张省力清单和鉴权方案对照表,避开 token 过期、越权访问、密码明文三类事故

你的产品到了要「认人」的阶段:谁注册的、谁正在登录、谁是付费会员能进 VIP 页、谁只是免费用户。听起来不复杂,你打开编辑器准备自己写一套登录注册——然后开始踩雷:密码该怎么存?用户登录后怎么记住他「已登录」?怎么防止张三构造个请求就访问了李四的数据?每一个问题背后都是一堆安全细节,写错一个,要么被脱库、要么被越权。好消息是:用户系统是最不该从零造轮子的东西。 这一节就告诉你一个人开发怎么用最省力、又不出安全事故的方式,给产品装上「认人」的能力。

这篇适合谁:你已经能做出能跑、能部署、有后端的产品(前面部署上线数据库与后端讲过了),现在想加「用户登录注册」,但既怕自己写的不安全,又被「会话、JWT、OAuth、鉴权、授权」这堆词绕晕。读完你会知道该用哪种省力方案,看懂认人这件事的最小流程,记住几条绝不能破的安全红线。

提醒:鉴权方案的具体接入字段、控制台路径、免费额度会变,本文讲不变的机制和安全原则,具体接入步骤以各家官方文档为准、规则会变


第一原则:别从零造轮子

「登录注册」看着简单,但一套真正安全的用户系统要处理的东西多到吓人:密码安全存储、防暴力破解、会话管理、邮箱验证、找回密码、第三方登录、防 CSRF……每一项都有专门的安全坑,自己从零写,等于把这些坑全亲手踩一遍。 对一个人开发的产品来说,这是巨大的浪费,何况大概率写得不如成熟方案安全。

所以省力的核心思路就一句:把「认人」这件专业又危险的活,交给专门做这个的托管服务,你只管业务。 具体有两条最省力的路:

路子一:托管鉴权服务

Supabase Auth、Auth0、Clerk 这类服务,把整套用户系统打包好了:注册、登录、密码加密存储、找回密码、邮箱验证、甚至现成的登录界面,你接进来就能用,安全细节它们替你扛。你写的代码量从「自己实现一整套」缩到「调几个它的接口」。一个人开发,这是首选。

路子二:社交登录(用微信/Google 等账号登录)

让用户「用微信登录」「用 Google 登录」「用 GitHub 登录」,好处是用户连密码都不用设——你压根不碰密码,也就没有「密码被脱库」的风险。认证交给微信、Google 这些大厂,它们的安全比你强得多。对面向开发者或海外用户的产品,社交登录体验好、注册转化高,很多托管鉴权服务也内置了它。

一句话选型:一个人做产品,能用托管鉴权就别自己写;能让用户用社交账号登录,就少存一份密码。 自己从零撸用户系统,只在你确实有特殊合规要求、且团队有安全能力时才考虑。


原理:「注册 → 登录 → 受保护接口校验」最小流程

不管用哪种方案,认人这件事的骨架是一样的。看懂它,你才知道托管服务到底替你做了什么。

注册
  用户填邮箱+密码 → 后端把密码用 hash+salt 加密后存库(绝不存明文)
                  → 库里那条记录是「这人是谁」的根

登录
  用户填邮箱+密码 → 后端取出库里的 hash,把这次输入的密码同样算一遍 hash
                  → 两个 hash 一致 = 密码对 → 发给用户一张「凭证」(会话ID 或 token)
                  → 用户后续每次请求都带上这张凭证

受保护接口校验(比如访问「我的订单」)
  用户带着凭证来 → 后端先验凭证:这凭证有效吗?是谁的?
                 → 确认是「张三」→ 再查:张三有权看这个吗?
                 → 都通过才返回数据,否则拒绝

这里藏着两个常被混为一谈、但必须分清的概念:

  • 鉴权(Authentication,认证):你是谁?——靠密码或社交账号确认身份。
  • 授权(Authorization,权限):你能干什么?——确认身份后,再判断这个人有没有权访问这个资源。

登录成功只解决了「你是谁」,不等于「你什么都能看」。 很多越权事故就出在:验过身份就放行,忘了再判一次「这个身份有没有权看这条具体数据」。


会话 vs JWT:凭证怎么发,怎么选

登录成功后发给用户的那张「凭证」,主流有两种,新手常纠结。给你直接结论:

  • 会话(Session):凭证只是一个无意义的 ID,真正的用户信息存在你服务器端。用户带 ID 来,服务器拿 ID 去查「这是谁」。好处是想让谁下线,服务器删掉那条会话即可,踢人/失效很干脆;代价是服务器要存会话状态。
  • JWT(Token):凭证本身是一段自带用户信息、且被签名的字符串,服务器不用存,验签通过就认。好处是无状态、适合多服务/前后端分离;代价是发出去就难主动作废——没到过期时间,它一直有效,想提前踢人得额外做「黑名单」。

给一个人开发的判断口诀:

  • 如果你用托管鉴权服务,用它默认给你的那套就好,别纠结。 Supabase/Auth0/Clerk 自己处理好了凭证的签发与失效,你不用关心底层是会话还是 JWT。
  • 真要自己选:传统服务端渲染、想要「随时能踢人下线」→ 倾向会话前后端分离、多个服务要共享登录态 → 倾向 JWT,但务必给它设较短的过期时间,并想清楚怎么作废。

红线一:密码永远 hash+salt,绝不存明文

这是用户系统不可触碰的第一红线数据库里永远不能出现用户的明文密码。

为什么?因为数据库总有被脱库(被人拖走整张表)的风险。如果你存的是明文,一旦脱库,所有用户的密码当场全裸——偏偏很多人到处用同一个密码,你这一漏,连累的是他们的邮箱、银行。这是会上新闻、会被追责的重大事故。

正确做法:

  • 存 hash 不存原文:密码经过单向哈希算法变成一串「算得出、反推不回去」的乱码再存。登录时把用户输入的密码同样哈希一遍,比对两个 hash 是否相等——全程你的库里都没有原始密码
  • 加 salt(盐):给每个用户的密码哈希时混入一段随机值,让两个用同一个密码的人,存出来的 hash 也不一样,防止坏人用「彩虹表」批量破解。
  • 用专门的密码哈希算法:用为「存密码」设计的慢哈希算法(业界常用 bcrypt、scrypt、argon2 这类),别用普通的快哈希。具体选哪个、怎么配,以安全社区与官方库文档为准、规则会演进。

最省心的执行方式还是那句:用托管鉴权服务,它默认就帮你做对了这一切,你根本不用自己碰密码哈希。 自己存密码,才需要操心这些。


红线二:最小权限模型

权限设计也有一条朴素红线:默认谁都没权,按需一点点给,而不是默认全开、再去堵。

具体落到一人开发的产品上:

  • 每个接口都问一句「这事该谁能干」:删除文章,只能本人或管理员;看订单,只能看自己的。把「该谁能干」写进接口的判断里,别图省事「登录了就放行」。
  • 永远校验「资源归属」:用户请求看订单 #123,后端不能只看「他登录了」,还要查「订单 #123 是不是他的」。漏了这一步,就是经典越权——改个 ID 就能看别人的数据。
  • 管理员能力单独收口:能改别人数据、能改价格、能封号的「高危操作」,单独判一次「你是不是管理员」,别和普通能力混在一起。

口诀:身份校验回答「你是不是登录用户」,权限校验回答「这个具体资源你有没有权动」——两步都做,才不越权。


增量一:用户系统省力清单

照着这张清单做,一个人也能搭出又省力又安全的用户系统:

  • 优先用托管鉴权(Supabase Auth / Auth0 / Clerk 等),别从零造整套
  • 能用社交登录就用(微信/Google/GitHub),少存甚至不存密码
  • 若必须自己存密码,一定 hash+salt,用专门的密码哈希算法,绝不存明文
  • 凭证用托管服务默认的那套,自己实现 JWT 务必设较短过期时间并想好怎么作废
  • 每个受保护接口都校验身份,没有有效凭证一律拒绝
  • 每次访问具体资源都校验归属(这单/这篇是不是他的),防改 ID 越权
  • 高危操作单独判管理员权限,不和普通能力混放
  • 密钥/服务端密钥放环境变量,绝不硬编码进前端代码或提交到 git

增量二:鉴权方案对照表

方案 最适合 省力程度 主要权衡
托管鉴权(Supabase Auth/Auth0/Clerk 等) 一人开发、想最快接好且安全 最省力,整套打包 依赖第三方,额度/定价以官方为准
社交登录(微信/Google/GitHub) 面向开发者/海外、要高注册转化 很省力,不用管密码 用户得有对应账号;接入各家有差异
自建会话(Session) 传统服务端渲染、要随时踢人 中等,要自己管会话存储 服务器要存状态;安全细节自己扛
自建 JWT 前后端分离、多服务共享登录态 中等,但作废逻辑麻烦 发出去难主动失效,要配过期+黑名单

各托管服务的免费额度、接口字段会变,以官方文档为准、规则会变,别照旧文里的数字下结论。


故障排查:用户系统出问题时照这张表查

现象 最可能的原因 怎么办
用户用着用着突然被登出 / 接口报「未授权」 token/会话过期了,前端没处理过期 给凭证设合理过期时间;前端识别「过期」状态,引导重新登录或用 refresh 机制续期
张三能看到李四的订单/数据 越权:只验了身份,没验资源归属 在接口里加「这条资源是不是当前用户的」校验,把 ID 改成别人的应当被拒
登录总提示密码错,但密码明明对 注册和登录用的哈希方式/盐不一致,或大小写空格处理不一致 确保注册存 hash 和登录验 hash 用完全相同的算法与流程;用托管服务可绕开这类问题
数据库被脱库后用户密码全泄露 存了明文密码(重大事故) 立即停止明文存储,改 hash+salt;通知用户改密;复盘并接托管鉴权。涉及个人信息泄露有法律责任,以官方与专业人士为准
普通用户能调到管理员才该有的接口 高危操作没单独校验管理员权限 给管理操作单独加角色判断,默认拒绝,只放行确实是管理员的请求
前端能看到本不该暴露的密钥 把服务端密钥写进了前端代码 服务端密钥只放后端环境变量;前端只拿「公开可见」的那类 key

这张表里最该警觉的是第二行和第四行:越权(改个 ID 看别人数据)和明文密码(脱库即裸奔),是用户系统最常见也最致命的两类事故。


变体:产品早期,用户系统能简化到什么程度

如果你还在验证产品,别一上来就上全套鉴权。按需求阶梯来:

  • 完全不需要认人:纯展示、纯工具站,根本别加登录——很多产品其实不需要用户系统,加了反而劝退。
  • 只想知道「谁感兴趣」:用一个邮箱收集(Waitlist)就够,别做完整账号体系。
  • 真要账号了:直接上托管鉴权 + 社交登录,半小时接好,比自己写一周还安全

核心判断:用户系统是「需要时再加」的能力,不是「产品标配先写上」的功能。 早期能不认人就不认,要认就用最省力的托管方案,把精力留给真正决定产品生死的部分。


动手挑战

挑一个做了才算数:

  1. 给你的产品想清楚三个问题:要不要认人?如果要,用社交登录还是邮箱密码?哪些页面/接口是「登录才能进」的、哪些是「只能看自己的」?把答案写下来,再去接。
  2. 选一个托管鉴权服务(Supabase Auth 等),按它官方的「快速开始」接一个最小 demo:能注册、能登录、有一个「没登录就拒绝、登录了才返回数据」的接口。亲手跑通这一条流程。
  3. 进阶:故意制造一次越权——做两个用户,用 A 的凭证去请求 B 的数据,确认你的接口能正确拒绝。亲手堵一次越权,比看十遍文章都记得牢。

小结 · 你现在掌握了什么

  • 你知道用户系统是最不该从零造轮子的东西,一人开发优先用托管鉴权(Supabase Auth/Auth0/Clerk)或社交登录,最省力也最安全。
  • 你看懂了「注册 → 登录 → 受保护接口校验」的最小流程,分得清鉴权(你是谁)和授权(你能干什么),也知道会话和 JWT 各适合什么。
  • 你记住了两条红线:密码永远 hash+salt 不存明文权限按最小够用给且每次校验资源归属,并能用一张省力清单和对照表落地。

认人是产品从「一个工具」长成「有用户的服务」的分水岭。但这活儿专业又危险,聪明的做法不是自己硬写,而是站在成熟方案的肩膀上——把危险的活交给专业的人,你守住几条红线就够了。

下一步:能收钱、能认人之后,上线前还有一关绕不过去——安全和合规自查。去看本级「安全与合规:上线前的安全自查与备案」那一节,把密钥泄露、注入、越权这些上线必堵的漏洞和国内备案的硬要求过一遍;想看自己在整条路上的位置,对照三支柱路线图

👉 看看我们的 AI 编程实战体系课,或逛 AI 编程教程大全 把基本功打扎实。

📄 来源 / 自校链接

本文为学习整理,关键步骤与代码请结合下列官方来源验证。

内容有错、看不懂、或想看下一期?告诉我们 →

本文为学习与落地整理,AI 工具与平台更新较快,关键步骤请结合官方最新资料验证。见免责声明