Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
128 lines
2.7 KiB
Go
128 lines
2.7 KiB
Go
package utils
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/dgrijalva/jwt-go"
|
|
)
|
|
|
|
const (
|
|
userIDKey = "userId"
|
|
ipKey = "ip"
|
|
uaKey = "ua"
|
|
)
|
|
|
|
type IPClaims struct {
|
|
Ip string
|
|
Expire time.Duration
|
|
UA string
|
|
}
|
|
|
|
func GenerateIpToken(claims IPClaims, secret string) (string, error) {
|
|
return generateToken(jwt.MapClaims{
|
|
ipKey: claims.Ip,
|
|
uaKey: claims.UA,
|
|
"exp": Now().Add(claims.Expire).Unix(),
|
|
"issuer": "com.butterfly",
|
|
"sub": "asign",
|
|
"aud": "public",
|
|
}, []byte(secret))
|
|
}
|
|
|
|
func ParseIpToken(tokenString string, secret string) (pass bool, ip, ua string, err error) {
|
|
t, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
|
return []byte(secret), nil
|
|
})
|
|
var isExpire *bool
|
|
if vErr, ok := err.(*jwt.ValidationError); ok {
|
|
e := vErr.Errors&jwt.ValidationErrorExpired > 0
|
|
isExpire = &e
|
|
}
|
|
if err != nil || isExpire == nil {
|
|
return
|
|
}
|
|
var ok bool
|
|
var jc jwt.MapClaims
|
|
jc, ok = t.Claims.(jwt.MapClaims)
|
|
if !ok {
|
|
err = errors.New("parse token fail")
|
|
return
|
|
}
|
|
ip, ok = jc[ipKey].(string)
|
|
if !ok {
|
|
err = errors.New("parse token fail")
|
|
return
|
|
}
|
|
ua, ok = jc[uaKey].(string)
|
|
if !ok {
|
|
err = errors.New("parse token fail")
|
|
return
|
|
}
|
|
pass = true
|
|
return
|
|
}
|
|
|
|
type UserClaims struct {
|
|
UserID int64
|
|
Expire time.Duration
|
|
}
|
|
|
|
func generateToken(claims jwt.MapClaims, secret []byte) (string, error) {
|
|
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(secret)
|
|
}
|
|
|
|
func GenerateUserToken(claims UserClaims, secret string) (string, error) {
|
|
return generateToken(jwt.MapClaims{
|
|
userIDKey: claims.UserID,
|
|
"exp": Now().Add(claims.Expire).Unix(),
|
|
"issuer": "com.butterfly",
|
|
"sub": "asign",
|
|
"aud": "public",
|
|
}, []byte(secret))
|
|
}
|
|
|
|
// ParseToken 解析Token
|
|
func ParseUserToken(token string, secret string) (userId int64, newToken string, err error) {
|
|
t, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
|
return []byte(secret), nil
|
|
})
|
|
var isExpire *bool
|
|
if vErr, ok := err.(jwt.ValidationError); ok {
|
|
e := vErr.Errors&jwt.ValidationErrorExpired > 0
|
|
isExpire = &e
|
|
}
|
|
if err != nil && isExpire == nil {
|
|
return
|
|
}
|
|
|
|
jc, ok := t.Claims.(jwt.MapClaims)
|
|
if !ok {
|
|
err = errors.New("unknown token error1")
|
|
return
|
|
}
|
|
|
|
id, ok := jc[userIDKey].(float64)
|
|
if !ok {
|
|
err = errors.New("unknown token error1")
|
|
return
|
|
}
|
|
userId = int64(id)
|
|
if isExpire != nil && *isExpire {
|
|
newToken, err = GenerateUserToken(UserClaims{UserID: userId, Expire: 30 * 24 * time.Hour}, secret)
|
|
return
|
|
}
|
|
err = nil
|
|
return
|
|
}
|
|
|
|
// Strips 'Bearer ' prefix from bearer token string
|
|
func StripBearerPrefixFromTokenString(tok string) string {
|
|
if len(tok) > 6 && strings.ToUpper(tok[0:7]) == "BEARER " {
|
|
return tok[7:]
|
|
} else {
|
|
return tok
|
|
}
|
|
}
|