package server import ( "crypto/hmac" "crypto/rand" "crypto/sha256" "encoding/base64" "encoding/json" "errors" "strings" "time" ) // SRS 推流 JWT(HS256)。服务端签发、并在 WHIP 反代层校验 role=publish, // 形成「分发入口」的访问控制。Cloudflare 走自身 AppSecret,无需此 token。 func b64url(b []byte) string { return base64.RawURLEncoding.EncodeToString(b) } type streamClaims struct { Room string `json:"room"` Identity string `json:"identity"` Role string `json:"role"` Exp int64 `json:"exp"` Iat int64 `json:"iat"` } func signStreamToken(secret, room, identity, role string, ttl time.Duration) (string, error) { now := time.Now() c := streamClaims{Room: room, Identity: identity, Role: role, Iat: now.Unix(), Exp: now.Add(ttl).Unix()} payload, _ := json.Marshal(c) header, _ := json.Marshal(map[string]string{"alg": "HS256", "typ": "JWT"}) signing := b64url(header) + "." + b64url(payload) mac := hmac.New(sha256.New, []byte(secret)) mac.Write([]byte(signing)) return signing + "." + b64url(mac.Sum(nil)), nil } func verifyStreamToken(secret, token string) (*streamClaims, error) { parts := strings.Split(token, ".") if len(parts) != 3 { return nil, errors.New("bad token") } mac := hmac.New(sha256.New, []byte(secret)) mac.Write([]byte(parts[0] + "." + parts[1])) if !hmac.Equal([]byte(b64url(mac.Sum(nil))), []byte(parts[2])) { return nil, errors.New("bad signature") } p, err := base64.RawURLEncoding.DecodeString(parts[1]) if err != nil { return nil, err } var c streamClaims if err := json.Unmarshal(p, &c); err != nil { return nil, err } if c.Exp < time.Now().Unix() { return nil, errors.New("token expired") } return &c, nil } func randomID() string { b := make([]byte, 9) rand.Read(b) return base64.RawURLEncoding.EncodeToString(b) }