137 lines
3.7 KiB
Go
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
|
|
}
|