登录必须用 bcrypt.comparehashandpassword 校验,禁止明文比对;数据库密码字段需为 text 或 varchar(255);fiber 中需用 session 或 jwt 管理状态,禁用 ctx.locals 跨请求存用户信息。

登录接口必须校验密码但不能明文比对
直接用 == 或 strings.EqualFold 比对前端传来的密码和数据库存的哈希值,永远失败。Fiber 本身不处理密码逻辑,你得自己集成安全方案。
推荐用 golang.org/x/crypto/bcrypt:注册时调用 bcrypt.GenerateFromPassword 存哈希;登录时用 bcrypt.CompareHashAndPassword 校验。别手写盐值或用 MD5/SHA —— 这些在 Fiber 里跑得再快也没用,因为根本不安全。
- 数据库字段类型必须是
TEXT或足够长的VARCHAR(bcrypt 哈希约 60 字符) - 如果用 GORM,记得对密码字段加
-tag,避免自动 SELECT 或 UPDATE 时暴露 -
CompareHashAndPassword第二个参数必须是原始字节切片([]byte(pwd)),不是字符串直接传
登录成功后必须用 Fiber 的 Session 或 JWT 管理状态
Fiber 默认无 session 支持,ctx.UserContext() 只是请求上下文,不跨请求存活。硬塞 ctx.Locals 然后以为能拿给下一个中间件用?不行 —— 它只在当前请求生命周期有效。
两种主流做法:
- 用
github.com/gofiber/fiber/v2/middleware/session:配置 Redis 或内存存储,session.New()后通过s.Get("user_id")存取,注意调用s.Save() - 用 JWT:签发
jwt.NewWithClaims+token.SignedString,把 token 放响应头Authorization: Bearer xxx,前端后续请求带上;服务端用jwt.Parse验签并提取 payload - 别把用户 ID 或角色写死进 cookie 值里(比如
SetCookie("uid", "123")),没签名极易被伪造
登录路由要禁用 BodyLimit 并显式解析 JSON
默认 f.Register 或 f.Post 不会拒绝超大请求体,但若你加了全局 fiber.BodyLimit(2 * 1024)(2KB),而用户密码含 Unicode 或调试时传了多余字段,就可能触发 413 Payload Too Large —— 这错误跟登录逻辑无关,却卡在网关层。
正确做法是在登录路由单独放开限制,并显式调用 ctx.Body() 或 ctx.JSON() 解析:
app.Post("/login", func(c *fiber.Ctx) error {
c.Locals("bodyLimit", "disabled") // 若用了自定义中间件控制 limit
var req struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid json"})
}
// ...校验逻辑
})
- 别依赖
ctx.FormValue读 JSON 字段 —— 它只处理application/x-www-form-urlencoded - 如果前端用
fetch发 JSON,确保 header 有Content-Type: application/json - BodyParser 默认最大解析 4MB,够用;真需要更大,改
f.Config().BodyLimit,别只调小
必须区分「用户不存在」和「密码错误」返回消息
返回 {"error": "用户名或密码错误"} 看似省事,实则给暴力破解留了路 —— 攻击者可先枚举用户名,再集中爆破密码。合规系统应统一返回模糊提示,但后端日志里记清真实原因。
- 先查用户是否存在:用
db.Where("username = ?", req.Username).First(&user) - 查不到就记录
login_attempt_failed: user_not_found到日志,返回通用错误 - 查到了再校验密码,失败则记
login_attempt_failed: wrong_password,同样返回通用错误 - 别在响应里暴露
user.ID、user.Status等字段,哪怕只是调试加的fmt.Printf
实际部署时,Redis session 的过期时间、JWT 的 exp 字段、密码重试锁定(如用 github.com/go-redis/redis_rate)这些都得补全,否则上线第一天就被扫号脚本盯上。











