feat: deliver authenticated task APIs, SDK and P1 regression

This commit is contained in:
2026-09-17 07:41:32 +08:00
parent 4f2935e36f
commit 9701b7a071
37 changed files with 3169 additions and 67 deletions

94
platform/auth/token.go Normal file
View File

@@ -0,0 +1,94 @@
// Package auth 定义凭据格式与权限快照;凭据原文仅在签发时交付。
package auth
import (
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"strings"
"git.yuntuo.hk/k2safe/orbit/internal/fault"
core "git.yuntuo.hk/k2safe/orbit/model"
)
// Token 是已解析但尚未认证的身份,服务端仍须核对数据库摘要与有效期。
type Token struct {
// NamespaceID 凭据所属命名空间,不能由请求体覆盖。
NamespaceID core.ID
// CredentialID 凭据记录标识。
CredentialID core.ID
// Digest 来自原始秘密的摘要,不包含可重放的原始秘密。
Digest core.Digest
}
func Issue(namespace, credential core.ID) (string, core.Digest, error) {
if err := namespace.Validate(); err != nil {
return "", core.Digest{}, err
}
if err := credential.Validate(); err != nil {
return "", core.Digest{}, err
}
var secret [32]byte
if _, err := rand.Read(secret[:]); err != nil {
return "", core.Digest{}, err
}
return "orb1." + string(namespace) + "." + string(credential) + "." + base64.RawURLEncoding.EncodeToString(secret[:]), core.Digest(sha256.Sum256(secret[:])), nil
}
func Parse(value string) (Token, error) {
p := strings.Split(value, ".")
if len(p) != 4 || p[0] != "orb1" || len(p[3]) != 43 {
return Token{}, fault.Unauthorized
}
ns, id := core.ID(p[1]), core.ID(p[2])
if ns.Validate() != nil || id.Validate() != nil {
return Token{}, fault.Unauthorized
}
secret, err := base64.RawURLEncoding.Strict().DecodeString(p[3])
if err != nil || len(secret) != 32 {
return Token{}, fault.Unauthorized
}
return Token{NamespaceID: ns, CredentialID: id, Digest: core.Digest(sha256.Sum256(secret))}, nil
}
// Permissions 是凭据的授权快照,动作与队列范围必须同时匹配。
type Permissions struct {
// Actions 明确授权的动作集合,首版不使用动作通配符。
Actions []string `json:"actions"`
// Queues 可访问的队列 ID;星号表示当前命名空间内全部队列。
Queues []string `json:"queues"`
}
var supported = map[string]bool{"tasks:submit": true, "tasks:read": true, "tasks:cancel": true, "queues:read": true, "queues:manage": true}
func (p Permissions) Validate() error {
if len(p.Actions) == 0 || len(p.Actions) > 32 || len(p.Queues) == 0 || len(p.Queues) > 128 {
return fault.Invalid("invalid permission scope")
}
for _, a := range p.Actions {
if !supported[a] {
return fault.Invalid("unsupported permission action")
}
}
for _, q := range p.Queues {
if q != "*" && core.ID(q).Validate() != nil {
return fault.Invalid("invalid queue permission")
}
}
return nil
}
func (p Permissions) Allows(action string) bool {
for _, a := range p.Actions {
if a == action {
return true
}
}
return false
}
func (p Permissions) AllowsQueue(queue core.ID) bool {
for _, q := range p.Queues {
if q == "*" || q == string(queue) {
return true
}
}
return false
}