新增总/子分类与曲目绑定;playlist 可按 categoryId 筛选并返回分类树; popadmin 支持行内改曲名/排序/上下架/会员开关与封面背景音频上传;文档同步。 Co-authored-by: Cursor <cursoragent@cursor.com>
87 lines
2.2 KiB
Go
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)
|
|
}
|