feat/create_new_token #2
|
@ -1,20 +1,57 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
mts "ark-permission/internal/lib/metric"
|
||||
|
||||
ers "code.30cm.net/wanderland/library-go/errors"
|
||||
"code.30cm.net/wanderland/library-go/errors/code"
|
||||
)
|
||||
|
||||
// Decimal: 120314
|
||||
// 12 represents Scope
|
||||
// 03 represents Category
|
||||
// 14 represents Detail error code
|
||||
// 100 represents Category
|
||||
// 9 represents Detail error code
|
||||
// full code 12009 只會有 系統以及錯誤碼,category 是給系統判定用的
|
||||
// 目前 Scope 以及分類要系統共用,係向的錯誤各自服務實作就好
|
||||
|
||||
const (
|
||||
TokenUnexpectedSigning = 1
|
||||
TokenUnexpectedSigningErrorCode = iota + 1
|
||||
TokenValidateErrorCode
|
||||
TokenClaimErrorCode
|
||||
)
|
||||
|
||||
// TokenUnexpectedSigningErr 031011
|
||||
const (
|
||||
RedisDelErrorCode = iota + 20
|
||||
RedisPipLineErrorCode
|
||||
)
|
||||
|
||||
// TokenUnexpectedSigningErr 30001 Token 簽名錯誤
|
||||
func TokenUnexpectedSigningErr(msg string) *ers.Err {
|
||||
return ers.NewErr(code.CloudEPPermission, code.CatInput, code.InvalidFormat, msg)
|
||||
mts.AppErrorMetrics.AddFailure("token", "token_unexpected_sign")
|
||||
return ers.NewErr(code.CloudEPPermission, code.CatInput, TokenUnexpectedSigningErrorCode, msg)
|
||||
}
|
||||
|
||||
// TokenTokenValidateErr 30002 Token 驗證錯誤
|
||||
func TokenTokenValidateErr(msg string) *ers.Err {
|
||||
mts.AppErrorMetrics.AddFailure("token", "token_validate_ilegal")
|
||||
return ers.NewErr(code.CloudEPPermission, code.CatInput, TokenValidateErrorCode, msg)
|
||||
}
|
||||
|
||||
// TokenClaimError 30003 Token 驗證錯誤
|
||||
func TokenClaimError(msg string) *ers.Err {
|
||||
mts.AppErrorMetrics.AddFailure("token", "token_claim_error")
|
||||
return ers.NewErr(code.CloudEPPermission, code.CatInput, TokenClaimErrorCode, msg)
|
||||
}
|
||||
|
||||
// RedisDelError 30020 Redis 刪除錯誤
|
||||
func RedisDelError(msg string) *ers.Err {
|
||||
// 看需要建立哪些 Metrics
|
||||
mts.AppErrorMetrics.AddFailure("redis", "del_error")
|
||||
return ers.NewErr(code.CloudEPPermission, code.CatDB, RedisDelErrorCode, msg)
|
||||
}
|
||||
|
||||
// RedisPipLineError 30021 Redis PipLine 錯誤
|
||||
func RedisPipLineError(msg string) *ers.Err {
|
||||
// 看需要建立哪些 Metrics
|
||||
mts.AppErrorMetrics.AddFailure("redis", "pip_line_error")
|
||||
return ers.NewErr(code.CloudEPPermission, code.CatInput, TokenClaimErrorCode, msg)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package metric
|
||||
|
||||
import (
|
||||
"github.com/zeromicro/go-zero/core/metric"
|
||||
)
|
||||
|
||||
var AppErrorMetrics = NewAppErrMetrics()
|
||||
|
||||
type appErrMetrics struct {
|
||||
metric.CounterVec
|
||||
}
|
||||
|
||||
type Metrics interface {
|
||||
AddFailure(source, reason string)
|
||||
}
|
||||
|
||||
// NewAppErrMetrics initiate metrics and register to prometheus
|
||||
func NewAppErrMetrics() Metrics {
|
||||
return &appErrMetrics{metric.NewCounterVec(&metric.CounterVecOpts{
|
||||
Namespace: "ark",
|
||||
Subsystem: "permission",
|
||||
Name: "permission_app_error_total",
|
||||
Help: "App defined failure total.",
|
||||
Labels: []string{"source", "reason"},
|
||||
})}
|
||||
}
|
||||
|
||||
func (m *appErrMetrics) AddFailure(source, reason string) {
|
||||
m.Inc(source, reason)
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
package metric
|
|
@ -3,6 +3,7 @@ package logic
|
|||
import (
|
||||
"ark-permission/gen_result/pb/permission"
|
||||
"ark-permission/internal/svc"
|
||||
ers "code.30cm.net/wanderland/library-go/errors"
|
||||
"context"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
@ -27,34 +28,38 @@ type cancelTokenReq struct {
|
|||
|
||||
// CancelToken 取消 Token,也包含他裡面的 One Time Toke
|
||||
func (l *CancelTokenLogic) CancelToken(in *permission.CancelTokenReq) (*permission.OKResp, error) {
|
||||
// // 驗證所需
|
||||
// if err := l.svcCtx.Validate.ValidateAll(&cancelTokenReq{
|
||||
// Token: in.GetToken(),
|
||||
// }); err != nil {
|
||||
// return nil, ers.InvalidFormat(err.Error())
|
||||
// }
|
||||
// 驗證所需
|
||||
if err := l.svcCtx.Validate.ValidateAll(&cancelTokenReq{
|
||||
Token: in.GetToken(),
|
||||
}); err != nil {
|
||||
return nil, ers.InvalidFormat(err.Error())
|
||||
}
|
||||
|
||||
// claims, err := uc.parseClaims(accessToken)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// token, err := uc.TokenRepository.GetByAccess(ctx, claims.ID())
|
||||
// if err != nil {
|
||||
// if errors.Is(err, repository.ErrRecordNotFound) {
|
||||
// return usecase.TokenError{Msg: "token not found"}
|
||||
// }
|
||||
//
|
||||
// return usecase.InternalError{Err: fmt.Errorf("tokenRepository.GetByAccess error: %w", err)}
|
||||
// }
|
||||
//
|
||||
// if err := uc.TokenRepository.Delete(ctx, token); err != nil {
|
||||
// if errors.Is(err, repository.ErrRecordNotFound) {
|
||||
// return nil, usecase.TokenError{Msg: "token not found"}
|
||||
// }
|
||||
//
|
||||
// return nil, err
|
||||
// }
|
||||
claims, err := parseClaims(l.ctx, in.GetToken(), l.svcCtx.Config.Token.Secret)
|
||||
if err != nil {
|
||||
logx.WithCallerSkip(1).WithFields(
|
||||
logx.Field("func", "parseClaims"),
|
||||
).Error(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
token, err := l.svcCtx.TokenRedisRepo.GetByAccess(l.ctx, claims.ID())
|
||||
if err != nil {
|
||||
logx.WithCallerSkip(1).WithFields(
|
||||
logx.Field("func", "TokenRedisRepo.GetByAccess"),
|
||||
logx.Field("claims", claims),
|
||||
).Error(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = l.svcCtx.TokenRedisRepo.Delete(l.ctx, token)
|
||||
if err != nil {
|
||||
logx.WithCallerSkip(1).WithFields(
|
||||
logx.Field("func", "TokenRedisRepo.Delete"),
|
||||
logx.Field("req", token),
|
||||
).Error(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &permission.OKResp{}, nil
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"ark-permission/internal/svc"
|
||||
ers "code.30cm.net/wanderland/library-go/errors"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"time"
|
||||
|
||||
|
@ -88,7 +87,11 @@ func (l *NewTokenLogic) NewToken(in *permission.AuthorizationReq) (*permission.T
|
|||
var err error
|
||||
token.AccessToken, err = generateAccessTokenFunc(token, claims, l.svcCtx.Config.Token.Secret)
|
||||
if err != nil {
|
||||
return nil, ers.ArkInternal(fmt.Errorf("accessGenerate token error: %w", err).Error())
|
||||
logx.WithCallerSkip(1).WithFields(
|
||||
logx.Field("func", "generateAccessTokenFunc"),
|
||||
logx.Field("claims", claims),
|
||||
).Error(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if in.GetIsRefreshToken() {
|
||||
|
@ -97,7 +100,11 @@ func (l *NewTokenLogic) NewToken(in *permission.AuthorizationReq) (*permission.T
|
|||
|
||||
err = l.svcCtx.TokenRedisRepo.Create(l.ctx, token)
|
||||
if err != nil {
|
||||
return nil, ers.ArkInternal(fmt.Errorf("tokenRepository.Create error: %w", err).Error())
|
||||
logx.WithCallerSkip(1).WithFields(
|
||||
logx.Field("func", "TokenRedisRepo.Create"),
|
||||
logx.Field("token", token),
|
||||
).Error(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &permission.TokenResp{
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"ark-permission/internal/domain"
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"ark-permission/gen_result/pb/permission"
|
||||
"ark-permission/internal/svc"
|
||||
"context"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
@ -29,8 +25,6 @@ func NewRefreshTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Refr
|
|||
// RefreshToken 更新目前的token 以及裡面包含的一次性 Token
|
||||
func (l *RefreshTokenLogic) RefreshToken(in *permission.RefreshTokenReq) (*permission.RefreshTokenResp, error) {
|
||||
// todo: add your logic here and delete this line
|
||||
e := domain.TokenUnexpectedSigningErr("gg88g88")
|
||||
fmt.Printf(strconv.Itoa(int(e.Code())), e.Category(), e.Scope(), e.FullCode(), e.Error())
|
||||
|
||||
return &permission.RefreshTokenResp{}, nil
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package logic
|
||||
|
||||
import (
|
||||
"ark-permission/internal/domain"
|
||||
"ark-permission/internal/entity"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
@ -23,7 +25,7 @@ func generateAccessToken(token entity.Token, data any, sign string) (string, err
|
|||
accessToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claim).
|
||||
SignedString([]byte(sign))
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", domain.TokenClaimError(err.Error())
|
||||
}
|
||||
|
||||
return accessToken, nil
|
||||
|
@ -37,40 +39,54 @@ func generateRefreshToken(accessToken string) string {
|
|||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
func parseClaims(accessToken string) (claims, error) {
|
||||
claimMap, err := parseToken(accessToken)
|
||||
func parseClaims(ctx context.Context, accessToken string, secret string) (claims, error) {
|
||||
claimMap, err := parseToken(ctx, accessToken, secret)
|
||||
if err != nil {
|
||||
return claims{}, err
|
||||
}
|
||||
|
||||
claims, ok := claimMap["data"].(map[string]string)
|
||||
claims, ok := claimMap["data"].(map[string]any)
|
||||
if ok {
|
||||
|
||||
return convertMap(claims), nil
|
||||
}
|
||||
|
||||
return nil, domain.TokenClaimError("get data from claim map error")
|
||||
}
|
||||
|
||||
func parseToken(ctx context.Context, accessToken string, secret string) (jwt.MapClaims, error) {
|
||||
token, err := jwt.Parse(accessToken, func(token *jwt.Token) (any, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, domain.TokenUnexpectedSigningErr(fmt.Sprintf("token unexpected signing method: %v", token.Header["alg"]))
|
||||
}
|
||||
|
||||
return []byte(secret), nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return jwt.MapClaims{}, err
|
||||
}
|
||||
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
|
||||
if !(ok && token.Valid) {
|
||||
return jwt.MapClaims{}, domain.TokenTokenValidateErr("token valid error")
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
return nil, 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)
|
||||
}
|
||||
|
||||
func parseToken(accessToken string) (jwt.MapClaims, error) {
|
||||
// token, err := jwt.Parse(accessToken, func(token *jwt.Token) (interface{}, error) {
|
||||
// if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
// return nil, domain.TokenUnexpectedSigningErr(fmt.Sprintf("token unexpected signing method: %v", token.Header["alg"]))
|
||||
// }
|
||||
//
|
||||
// return []byte(uc.Config.CustomConfig.Token.Secret), nil
|
||||
// })
|
||||
//
|
||||
// if err != nil {
|
||||
// ers.FromCode()
|
||||
// return jwt.MapClaims{}, usecase.TokenError{Msg: fmt.Sprintf("parse token error: %s token: %s", err.Error(), accessToken)}
|
||||
// }
|
||||
//
|
||||
// claims, ok := token.Claims.(jwt.MapClaims)
|
||||
//
|
||||
// if !(ok && token.Valid) {
|
||||
// return jwt.MapClaims{}, usecase.TokenError{Msg: "token valid error"}
|
||||
// }
|
||||
//
|
||||
// return claims, nil
|
||||
return nil, nil
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"ark-permission/internal/domain/repository"
|
||||
"ark-permission/internal/entity"
|
||||
ers "code.30cm.net/wanderland/library-go/errors"
|
||||
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
@ -32,7 +31,7 @@ func NewTokenRepository(param TokenRepositoryParam) repository.TokenRepository {
|
|||
func (t *tokenRepository) Create(ctx context.Context, token entity.Token) error {
|
||||
body, err := json.Marshal(token)
|
||||
if err != nil {
|
||||
return wrapError("json.Marshal token error", err)
|
||||
return ers.ArkInternal("json.Marshal token error", err.Error())
|
||||
}
|
||||
|
||||
err = t.store.Pipelined(func(tx redis.Pipeliner) error {
|
||||
|
@ -53,11 +52,11 @@ func (t *tokenRepository) Create(ctx context.Context, token entity.Token) error
|
|||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return wrapError("store.Pipelined error", err)
|
||||
return domain.RedisPipLineError(err.Error())
|
||||
}
|
||||
|
||||
if err := t.SetUIDToken(token); err != nil {
|
||||
return wrapError("SetUIDToken error", err)
|
||||
return ers.ArkInternal("SetUIDToken error", err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -76,7 +75,7 @@ func (t *tokenRepository) Delete(ctx context.Context, token entity.Token) error
|
|||
|
||||
for _, key := range keys {
|
||||
if err := tx.Del(ctx, key).Err(); err != nil {
|
||||
return fmt.Errorf("store.Del key error: %w", err)
|
||||
return domain.RedisDelError(fmt.Sprintf("store.Del key error: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +83,7 @@ func (t *tokenRepository) Delete(ctx context.Context, token entity.Token) error
|
|||
key := domain.DeviceTokenRedisKey.With(token.UID).ToString()
|
||||
_, err := t.store.Hdel(key, token.DeviceID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("store.HDel deviceKey error: %w", err)
|
||||
return domain.RedisDelError(fmt.Sprintf("store.HDel deviceKey error: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,7 +91,7 @@ func (t *tokenRepository) Delete(ctx context.Context, token entity.Token) error
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("store.Pipelined error: %w", err)
|
||||
return domain.RedisPipLineError(fmt.Sprintf("store.Pipelined error: %v", err))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -100,17 +99,17 @@ func (t *tokenRepository) Delete(ctx context.Context, token entity.Token) error
|
|||
|
||||
func (t *tokenRepository) get(key string) (entity.Token, error) {
|
||||
body, err := t.store.Get(key)
|
||||
if errors.Is(err, redis.Nil) {
|
||||
if errors.Is(err, redis.Nil) || body == "" {
|
||||
return entity.Token{}, ers.ResourceNotFound("token key not found in redis", key)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return entity.Token{}, fmt.Errorf("store.Get tokenTag error: %w", err)
|
||||
return entity.Token{}, ers.ArkInternal(fmt.Sprintf("store.Get tokenTag error: %v", err))
|
||||
}
|
||||
|
||||
var token entity.Token
|
||||
if err := json.Unmarshal([]byte(body), &token); err != nil {
|
||||
return entity.Token{}, fmt.Errorf("json.Unmarshal token error: %w", err)
|
||||
return entity.Token{}, ers.ArkInternal(fmt.Sprintf("json.Unmarshal token error: %w", err))
|
||||
}
|
||||
|
||||
return token, nil
|
||||
|
|
Loading…
Reference in New Issue