spark-server/internal/module/admin/logic/jwt.go
DESKTOP-L8OUL9F\gfl0034 d3a68c3cad feat(music): 分类多对多、后台完整编辑与 OpenAPI
新增总/子分类与曲目绑定;playlist 可按 categoryId 筛选并返回分类树;
popadmin 支持行内改曲名/排序/上下架/会员开关与封面背景音频上传;文档同步。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 10:38:06 +08:00

87 lines
2.2 KiB
Go

package logic
import (
"errors"
"strings"
"time"
"github.com/golang-jwt/jwt/v5"
)
const TypeAdmin = "admin"
var (
ErrInvalidToken = errors.New("invalid admin token")
ErrWrongType = errors.New("token type mismatch")
)
// Claims matches Java JwtTokenProvider admin tokens (popadmin.wyrs365.com).
type Claims struct {
AdminID int64 `json:"adminId"`
Role string `json:"role"`
Type string `json:"type"`
Permissions string `json:"permissions"`
AllowedSites string `json:"allowedSites"`
SiteRealm string `json:"siteRealm"`
jwt.RegisteredClaims
}
// TokenService validates HS256 admin JWTs issued by the Java / popadmin login.
type TokenService struct {
secret []byte
}
func NewTokenService(secret string) *TokenService {
sec := []byte(strings.TrimSpace(secret))
if len(sec) < 32 {
padded := make([]byte, 32)
copy(padded, sec)
sec = padded
}
return &TokenService{secret: sec}
}
func (s *TokenService) Parse(tokenStr string) (*Claims, error) {
if s == nil || len(s.secret) == 0 {
return nil, ErrInvalidToken
}
t, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(t *jwt.Token) (interface{}, error) {
// Java JwtTokenProvider signs with HS512; local CreateToken / tests use HS256.
switch t.Method {
case jwt.SigningMethodHS256, jwt.SigningMethodHS512:
return s.secret, nil
default:
return nil, ErrInvalidToken
}
})
if err != nil {
return nil, ErrInvalidToken
}
claims, ok := t.Claims.(*Claims)
if !ok || !t.Valid {
return nil, ErrInvalidToken
}
if claims.Type != "" && claims.Type != TypeAdmin {
return nil, ErrWrongType
}
return claims, nil
}
// CreateToken is for tests and local smoke only (production tokens come from Java login).
func (s *TokenService) CreateToken(adminID int64, username, role, permissions string) (string, error) {
now := time.Now()
claims := Claims{
AdminID: adminID,
Role: role,
Type: TypeAdmin,
Permissions: permissions,
RegisteredClaims: jwt.RegisteredClaims{
Subject: username,
IssuedAt: jwt.NewNumericDate(now),
ExpiresAt: jwt.NewNumericDate(now.Add(24 * time.Hour)),
},
}
tok := jwt.NewWithClaims(jwt.SigningMethodHS256, &claims)
return tok.SignedString(s.secret)
}