Revel中生成JWT访问令牌需借助第三方库(如golang-jwt/jwt/v5),在Controller中安全调用:使用HS256算法、环境变量加载密钥,payload至少含sub、exp、iat,避免敏感信息,通过RenderJSON返回token字符串。

Revel 中生成 JWT 访问令牌的典型做法
Revel 本身不内置令牌生成逻辑,得靠第三方库(如 github.com/dgrijalva/jwt-go 或更现代的 github.com/golang-jwt/jwt/v5)手动签发。关键不是“Revel 怎么做”,而是“你在 Revel 的 Controller 里怎么安全、可控地调用 JWT 库”。
常见错误是直接把用户密码或明文 ID 塞进 token payload,或者忽略 exp 字段导致令牌永不过期。
- 推荐用
jwt.SigningMethodHS256配合环境变量管理的密钥(如os.Getenv("JWT_SECRET")),别硬编码 - payload 至少包含
sub(用户标识)、exp(Unix 时间戳)、iat,避免传敏感字段(如邮箱、角色权限建议查库动态加载,不放 token 里) - Revel 的
Controller.RenderJSON()可直接返回 map 或 struct,但 token 要放在响应体里,不是 header —— 别和 HTTP Authentication header 混淆
在 Revel Controller 中实现登录并签发 token
典型场景:用户 POST /login 提交账号密码,验证通过后返回 JWT。这不是 Revel 特有流程,但要注意它对请求体解析和错误处理的习惯写法。
示例中假设你已用 revel.BEFORE 拦截器校验了 Content-Type: application/json,且用户模型已定义 User.FindByCredentials():
func (c App) Login() revel.Result {
var req struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := c.Params.BindJSON(&req); err != nil {
return c.RenderError("invalid JSON")
}
<pre class="brush:php;toolbar:false;">user, err := models.User.FindByCredentials(req.Username, req.Password)
if err != nil || user == nil {
return c.RenderError("invalid credentials")
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": user.ID,
"exp": time.Now().Add(24 * time.Hour).Unix(),
"iat": time.Now().Unix(),
})
jwtString, err := token.SignedString([]byte(os.Getenv("JWT_SECRET")))
if err != nil {
revel.ERROR.Printf("JWT sign error: %v", err)
return c.RenderError("token generation failed")
}
return c.RenderJSON(map[string]string{"token": jwtString})}
注意:Revel 默认会将 RenderJSON 的 map 自动序列化为 JSON 响应,状态码是 200;若需自定义状态码(比如登录失败返回 401),要用 c.RenderError 或 c.Response.Status = "401 Unauthorized"。
Revel 中验证 JWT 并提取用户信息的中间件写法
生成 token 只是第一步,后续接口需要从 Authorization: Bearer <token></token> 头里解析并校验它。Revel 没有“全局 auth middleware”概念,得自己用 revel.Interceptor 实现。
容易踩的坑:ParseWithClaims 不自动校验 exp,必须显式传入 jwt.WithValidMethods 和 jwt.WithExpirationRequired();另外 Revel 的 c.Request.Header.Get("Authorization") 返回的是完整字符串(如 Bearer xxx),得手动切分。
- 检查 header 是否存在,是否以
"Bearer "开头(注意空格) - 用
jwt.Parse+jwt.Keyfunc回调返回密钥,不要在闭包里硬写[]byte("secret") - 校验失败时,直接
return c.RenderError("unauthorized").(revel.Result),并设c.Response.Status = "401 Unauthorized" - 成功后把
claims["sub"]转成 int 或 string 存到c.Params.Values["user_id"],供后续 action 使用
为什么不用 Revel 自带的 session 而选 JWT
Revel 的 Session 是服务端存储(默认基于 cookie + memory store),适合简单场景;但 Web API 要求无状态、跨域、移动端友好 —— 这时候 JWT 更合适,因为所有认证信息都在客户端携带,服务端只需校验签名和有效期。
但别忽略代价:JWT 一旦签发无法主动作废(除非加黑名单或缩短有效期),且 payload 过大会增加每次请求体积。如果业务需要实时踢人、频繁刷新权限,JWT 就不是最优解,该回退到 session + redis 方案。
Revel 的 Session 和 JWT 不互斥,可以共存:比如用 Session 管理后台管理页,用 JWT 管理 API 接口。


















