package mcp import ( "crypto/rand" "crypto/sha256" "encoding/base64" "fmt" ) // tokenRawLen 是 plaintext 随机字节长度。32 字节 = 256 bit 熵, // base64.RawURL 编码后 43 字符(无 padding);加 "mcpt_" 前缀总 48 字符。 // // 与 user.NewSessionToken 的 24 字节比,MCP token 加大到 32 字节是因为: // admin 签发的 token 长期存在(90 天默认),熵预算更宽。 const tokenRawLen = 32 // tokenPrefix 是 plaintext 的肉眼可读前缀。鉴权时不参与 hash 计算 —— hash // 是对完整字符串(含前缀)做 SHA-256;前缀仅是日志/调试时区分用。 const tokenPrefix = "mcpt_" // NewToken 生成 (plaintext, hash) 对。plaintext 仅在签发时返回一次, // 后续认证只用 hash 反查。 func NewToken() (plaintext string, hash []byte, err error) { raw := make([]byte, tokenRawLen) if _, err := rand.Read(raw); err != nil { return "", nil, fmt.Errorf("rand: %w", err) } enc := base64.RawURLEncoding.EncodeToString(raw) plain := tokenPrefix + enc return plain, HashToken(plain), nil } // HashToken 对 token plaintext(含前缀)做 SHA-256,返回 32 字节固定长度。 // 纯函数:相同输入恒返回相同输出,便于鉴权时按请求中的明文反查 DB。 func HashToken(plaintext string) []byte { sum := sha256.Sum256([]byte(plaintext)) return sum[:] }