b5ab92a57e
来自 xhigh code review 的正确性/健壮性修复,覆盖全部五端: - server:鉴权 fail-closed、计量交叉校验与配额扣穿处理、WS 网关并发与关闭顺序、 billing 行锁、redis Lua 过期与设备槽刷新、config 解析 - desktop:会话 epoch 防串话、WS 重连与 401 处理、api 客户端复用、统一 usePoll 轮询 - android:握手时序、请求头封装、账户状态派生、按需重组 - ios:finalize 宽限、串行采集、错误文案服务端优先、删除死代码 CommitController Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
65 lines
1.7 KiB
Go
65 lines
1.7 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/alicebob/miniredis/v2"
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
func TestSignParseRevoke(t *testing.T) {
|
|
mr := miniredis.RunT(t)
|
|
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
|
j := NewJWT("test-secret", time.Hour, rdb)
|
|
ctx := context.Background()
|
|
|
|
token, err := j.Sign("u1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
uid, jti, exp, err := j.Parse(ctx, token)
|
|
if err != nil || uid != "u1" || jti == "" {
|
|
t.Fatalf("parse failed: uid=%s jti=%s err=%v", uid, jti, err)
|
|
}
|
|
if exp.IsZero() || time.Until(exp) <= 0 {
|
|
t.Fatalf("expiresAt should be in the future, got %v", exp)
|
|
}
|
|
|
|
// 拉黑后解析失败
|
|
if err := j.Revoke(ctx, jti, time.Now().Add(time.Hour)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, _, _, err := j.Parse(ctx, token); err == nil {
|
|
t.Fatal("expect parse failure after revoke")
|
|
}
|
|
|
|
// 篡改签名失败
|
|
if _, _, _, err := j.Parse(ctx, token+"x"); err == nil {
|
|
t.Fatal("expect parse failure on tampered token")
|
|
}
|
|
}
|
|
|
|
// TestParseFailClosed Redis 不可用时黑名单检查应 fail-closed:拒绝放行(17A)。
|
|
func TestParseFailClosed(t *testing.T) {
|
|
mr := miniredis.RunT(t)
|
|
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
|
|
j := NewJWT("test-secret", time.Hour, rdb)
|
|
ctx := context.Background()
|
|
|
|
token, err := j.Sign("u1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// 正常情况下放行
|
|
if _, _, _, err := j.Parse(ctx, token); err != nil {
|
|
t.Fatalf("parse should pass while redis up: %v", err)
|
|
}
|
|
// Redis 故障:Exists 返回 error → 必须拒绝(不得 fail-open)。
|
|
mr.Close()
|
|
if _, _, _, err := j.Parse(ctx, token); err == nil {
|
|
t.Fatal("expect parse failure when redis is unavailable (fail-closed)")
|
|
}
|
|
}
|