认证鉴权
认证鉴权
认证用于确认“你是谁”,鉴权用于判断“你能做什么”。golang-jwt/jwt 负责签发和验证 JWT,Casbin 负责根据策略判断访问权限,两者解决的问题不同。
go get github.com/golang-jwt/jwt/v5
go get github.com/casbin/casbin/v3
JWT 身份认证
签发 Token 时使用标准 Claims,并设置明确的过期时间、签发者和受众:
type Claims struct {
UserID string `json:"user_id"`
jwt.RegisteredClaims
}
claims := Claims{
UserID: "user-1",
RegisteredClaims: jwt.RegisteredClaims{
Issuer: "api.example.com",
Audience: jwt.ClaimStrings{"web.example.com"},
Subject: "user-1",
ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * time.Minute)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(secret)
解析时应限制允许的签名算法,并校验签发者和受众:
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (any, error) {
return secret, nil
},
jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}),
jwt.WithIssuer("api.example.com"),
jwt.WithAudience("web.example.com"),
)
if err != nil || !token.Valid {
return errors.New("invalid token")
}
claims, ok := token.Claims.(*Claims)
生产环境应从密钥管理系统读取密钥,不要硬编码。短期 Access Token 通常搭配可撤销的 Refresh Token;JWT 的 Payload 只是编码,不应存放密码或其他敏感信息。
Casbin 权限控制
Casbin 将访问模型和权限策略分开。下面使用 RBAC 模型与策略文件创建 Enforcer:
enforcer, err := casbin.NewEnforcer("model.conf", "policy.csv")
if err != nil {
return err
}
allowed, err := enforcer.Enforce("alice", "/orders", "read")
if err != nil {
return err
}
if !allowed {
return errors.New("permission denied")
}
model.conf 定义请求、策略、角色和匹配规则:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
policy.csv 保存角色权限和用户角色关系:
p, admin, /orders, read
p, admin, /orders, write
g, alice, admin
生产项目通常通过 Adapter 把策略保存到数据库,并在策略变化时同步多个服务实例。鉴权应默认拒绝访问,不能因为 Casbin 执行出错而放行请求。
组合流程
- 从请求头读取 Bearer Token,并使用 JWT 验证身份。
- 从 Claims 中取得用户 ID,不能直接信任客户端提交的身份。
- 将用户、资源和操作传给 Casbin 执行鉴权。
- 只有认证和鉴权都成功后,才调用业务逻辑。