backend/pkg/permission/usecase/token_jwt.go

108 lines
2.5 KiB
Go
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package usecase
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"time"
"backend/pkg/permission/domain/entity"
"github.com/golang-jwt/jwt/v4"
)
var accessTokenGenerator = createAccessToken
var refreshTokenGenerator = createRefreshToken
// createAccessToken 生成訪問令牌Access Token
func createAccessToken(token entity.Token, data any, secretKey string) (string, error) {
claims := entity.Claims{
Data: data,
RegisteredClaims: jwt.RegisteredClaims{
ID: token.ID,
ExpiresAt: jwt.NewNumericDate(time.Unix(int64(token.ExpiresIn), 0)),
Issuer: "permission",
},
}
accessToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).
SignedString([]byte(secretKey))
if err != nil {
return "", err
}
return accessToken, nil
}
// createRefreshToken 基於訪問令牌生成刷新令牌Refresh Token
func createRefreshToken(accessToken string) string {
hash := sha256.New()
_, _ = hash.Write([]byte(accessToken))
return hex.EncodeToString(hash.Sum(nil))
}
func parseToken(accessToken string, secret string, validate bool) (jwt.MapClaims, error) {
// 跳過驗證的解析
var token *jwt.Token
var err error
if validate {
token, err = jwt.Parse(accessToken, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("token unexpected signing method: %v", token.Header["alg"])
}
return []byte(secret), nil
})
if err != nil {
return jwt.MapClaims{}, err
}
} else {
parser := jwt.NewParser(jwt.WithoutClaimsValidation())
token, err = parser.Parse(accessToken, func(_ *jwt.Token) (any, error) {
return []byte(secret), nil
})
if err != nil {
return jwt.MapClaims{}, err
}
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok && token.Valid {
return jwt.MapClaims{}, fmt.Errorf("token valid error")
}
return claims, nil
}
func parseClaims(accessToken string, secret string, validate bool) (tokenClaims, error) {
claimMap, err := parseToken(accessToken, secret, validate)
if err != nil {
return tokenClaims{}, err
}
claimsData, ok := claimMap["data"].(map[string]any)
if ok {
return convertMap(claimsData), nil
}
return tokenClaims{}, fmt.Errorf("get data from claim map error")
}
func convertMap(input map[string]interface{}) map[string]string {
output := make(map[string]string)
for key, value := range input {
switch v := value.(type) {
case string:
output[key] = v
case fmt.Stringer:
output[key] = v.String()
default:
output[key] = fmt.Sprintf("%v", value)
}
}
return output
}