最稳妥方案是用 gorilla/sessions 管理登录态,它默认启用 HttpOnly、Secure 和 SameSite,支持多种后端存储,且避免手动操作 cookie 的安全风险。
用 gorilla/sessions 管理登录态最稳妥
Go 标准库没有开箱即用的会话管理方案,直接操作 http.SetCookie 容易漏掉 HttpOnly、Secure、SameSite 等关键属性,还容易被 CSRF 或会话固定攻击利用。推荐用 gorilla/sessions,它默认启用 HttpOnly 和 Secure(生产环境需配 HTTPS),并支持多种后端存储(内存、Redis、PostgreSQL)。
实操建议:
- 使用基于加密密钥的
cookiestore时,密钥长度必须 ≥ 32 字节,否则启动报错:crypto/aes: invalid key size 16 - 不要把用户密码、token 原样存进 session;只存
user_id,后续请求通过 ID 查数据库获取权限信息 - 登录成功后调用
session.Save(r, w),否则 cookie 不会写入响应头 - 退出时用
session.Options.MaxAge = -1并调用Save,强制客户端删除 cookie
store := cookie.NewCookieStore([]byte("32-byte-secret-key-must-be-long-enough"))
store.Options = &sessions.Options{
HttpOnly: true,
Secure: true, // 生产环境必须为 true(HTTPS 下)
SameSite: http.SameSiteStrictMode,
}
JWT 认证适合无状态 API,但别手写签名逻辑
如果做前后端分离的 REST API,JWT 是更自然的选择;但 Go 生态里别自己拼字符串 + base64 + HMAC,容易出错。用 golang-jwt/jwt/v5(原 dgrijalva/jwt-go 的维护分支)更安全。
常见错误现象:
- 用
SigningMethodHS256但密钥硬编码在代码里,且未轮换 —— 一旦泄露,所有 token 失效风险高 - 校验时没检查
exp和nbf字段,导致过期 token 仍被接受 - 把 JWT 放在 URL 参数或 body 里传,而不是
Authorization: Bearer头中
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"user_id": 123,
"exp": time.Now().Add(24 * time.Hour).Unix(),
})
signedToken, _ := token.SignedString([]byte("your-32-byte-secret"))
中间件里统一校验登录态,避免每个 handler 重复写
认证逻辑不该散落在各个 HTTP handler 里。用中间件封装校验流程,既减少重复,也便于统一处理未授权响应(如返回 401 或重定向到登录页)。