Files
EveryPublish/server/internal/auth/jwt.go
T

137 lines
3.7 KiB
Go

package auth
import (
"errors"
"time"
"github.com/golang-jwt/jwt/v5"
)
// 过期策略:Access 15 分钟 / Refresh 7 天(旋转)/ Invite 24 小时
const (
AccessTTL = 15 * time.Minute
RefreshTTL = 7 * 24 * time.Hour
InviteTTL = 24 * time.Hour
)
// AccessClaims 访问令牌声明
type AccessClaims struct {
UID uint64 `json:"uid"`
WorkspaceID uint64 `json:"wsid"`
Role string `json:"role"`
MemberRole string `json:"mrole"`
jwt.RegisteredClaims
}
// RefreshClaims 刷新令牌声明
type RefreshClaims struct {
UID uint64 `json:"uid"`
WorkspaceID uint64 `json:"wsid"`
JTI string `json:"jti"`
jwt.RegisteredClaims
}
// InviteClaims 邀请令牌声明
type InviteClaims struct {
WorkspaceID uint64 `json:"wsid"`
Email string `json:"email"`
Role string `json:"role"`
jwt.RegisteredClaims
}
// IssueAccess 签发访问令牌
func IssueAccess(secret string, uid, wsid uint64, role, memberRole string) (string, error) {
now := time.Now()
claims := AccessClaims{
UID: uid, WorkspaceID: wsid, Role: role, MemberRole: memberRole,
RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(now),
ExpiresAt: jwt.NewNumericDate(now.Add(AccessTTL)),
Issuer: "everypublish",
},
}
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
}
// IssueRefresh 签发刷新令牌
func IssueRefresh(secret string, uid, wsid uint64, jti string) (string, error) {
now := time.Now()
claims := RefreshClaims{
UID: uid, WorkspaceID: wsid, JTI: jti,
RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(now),
ExpiresAt: jwt.NewNumericDate(now.Add(RefreshTTL)),
Issuer: "everypublish",
},
}
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
}
// IssueInvite 签发邀请令牌
func IssueInvite(secret string, wsid uint64, email, role string) (string, error) {
now := time.Now()
claims := InviteClaims{
WorkspaceID: wsid, Email: email, Role: role,
RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(now),
ExpiresAt: jwt.NewNumericDate(now.Add(InviteTTL)),
Issuer: "everypublish",
},
}
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
}
// ParseAccess 解析访问令牌
func ParseAccess(secret, token string) (*AccessClaims, error) {
claims := &AccessClaims{}
parsed, err := jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, errors.New("unexpected signing method")
}
return []byte(secret), nil
})
if err != nil {
return nil, err
}
if !parsed.Valid {
return nil, errors.New("invalid token")
}
return claims, nil
}
// ParseRefresh 解析刷新令牌
func ParseRefresh(secret, token string) (*RefreshClaims, error) {
claims := &RefreshClaims{}
parsed, err := jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, errors.New("unexpected signing method")
}
return []byte(secret), nil
})
if err != nil {
return nil, err
}
if !parsed.Valid {
return nil, errors.New("invalid token")
}
return claims, nil
}
// ParseInvite 解析邀请令牌
func ParseInvite(secret, token string) (*InviteClaims, error) {
claims := &InviteClaims{}
parsed, err := jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, errors.New("unexpected signing method")
}
return []byte(secret), nil
})
if err != nil {
return nil, err
}
if !parsed.Valid {
return nil, errors.New("invalid token")
}
return claims, nil
}