173 lines
4.1 KiB
Go
173 lines
4.1 KiB
Go
package logic
|
||
|
||
import (
|
||
"fmt"
|
||
tokenproto "service/api/proto/token/proto"
|
||
"service/app/mix/dao"
|
||
"service/dbstruct"
|
||
"service/library/configcenter"
|
||
"service/library/idgenerator"
|
||
"service/library/logger"
|
||
"strconv"
|
||
"time"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/golang-jwt/jwt/v5"
|
||
)
|
||
|
||
type Token struct {
|
||
store *dao.Store
|
||
cryptoConfig *configcenter.CryptoConfig
|
||
}
|
||
|
||
func NewToken(store *dao.Store, cryptoConfig *configcenter.CryptoConfig) (a *Token) {
|
||
a = &Token{
|
||
store: store,
|
||
cryptoConfig: cryptoConfig,
|
||
}
|
||
return
|
||
}
|
||
|
||
// Token
|
||
func (p *Token) OpCreate(ctx *gin.Context, req *tokenproto.OpCreateReq) error {
|
||
req.Token.Ct = time.Now().Unix()
|
||
err := p.store.CreateToken(ctx, req.Token)
|
||
if err != nil {
|
||
logger.Error("CreateToken fail, err: %v", err)
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (p *Token) OpDelete(ctx *gin.Context, id int64) error {
|
||
err := p.store.DeleteToken(ctx, id)
|
||
if err != nil {
|
||
logger.Error("DeleteToken fail, err: %v", err)
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (p *Token) OpDeleteByMid(ctx *gin.Context, mid int64) error {
|
||
err := p.store.DeleteTokenByMid(ctx, mid)
|
||
if err != nil {
|
||
logger.Error("OpDeleteByMid fail, err: %v", err)
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (p *Token) OpDeleteByMids(ctx *gin.Context, mids []int64) error {
|
||
err := p.store.DeleteTokenByMids(ctx, mids)
|
||
if err != nil {
|
||
logger.Error("OpDeleteByMids fail, err: %v", err)
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (p *Token) OpList(ctx *gin.Context, req *tokenproto.OpListReq) ([]*dbstruct.Token, error) {
|
||
list, err := p.store.GetTokenList(ctx, req)
|
||
if err != nil {
|
||
logger.Error("GetTokenList fail, err: %v", err)
|
||
return make([]*dbstruct.Token, 0), err
|
||
}
|
||
return list, nil
|
||
}
|
||
|
||
func (p *Token) OpGenerate(ctx *gin.Context, req *tokenproto.OpCreateReq) (token string, err error) {
|
||
|
||
//token在数据库里的唯一标识
|
||
token_uuid := idgenerator.GenTokenId()
|
||
|
||
//生成token
|
||
atClaims := jwt.MapClaims{
|
||
"authorized": true,
|
||
"token_uuid": token_uuid,
|
||
"mid": req.Token.Mid,
|
||
}
|
||
at := jwt.NewWithClaims(jwt.SigningMethodHS256, atClaims)
|
||
token, err = at.SignedString([]byte(p.cryptoConfig.TokenPrivateKey))
|
||
if err != nil {
|
||
logger.Error("OpGenerate generation of token failed, err: %v", err)
|
||
return "", err
|
||
}
|
||
|
||
//将token存入数据库
|
||
req.Token.Id = token_uuid
|
||
err = p.store.CreateToken(ctx, req.Token)
|
||
if err != nil {
|
||
logger.Error("OpGenerate failed, err: %v", err)
|
||
return "", err
|
||
}
|
||
return
|
||
}
|
||
|
||
func (p *Token) OpVerify(ctx *gin.Context, tokenString string) error {
|
||
|
||
//是否携带令牌
|
||
if tokenString == "" {
|
||
logger.Error("Missing auth token")
|
||
return fmt.Errorf("missing auth token")
|
||
}
|
||
|
||
//检查令牌加密方法及签名
|
||
token, err := p.OpVerifyCrypto(ctx, tokenString)
|
||
if err != nil {
|
||
logger.Error("OpVerifyCrypto failed")
|
||
return err
|
||
}
|
||
|
||
//检查数据库中是否还存在该token(是否还有效)
|
||
err = p.OpVerifyValid(ctx, token)
|
||
if err != nil {
|
||
logger.Error("OpVerifyValid failed")
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// 检查令牌加密方法及签名
|
||
func (p *Token) OpVerifyCrypto(ctx *gin.Context, tokenString string) (token *jwt.Token, err error) {
|
||
token, err = jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||
}
|
||
return []byte(p.cryptoConfig.TokenPrivateKey), nil
|
||
})
|
||
if err != nil {
|
||
logger.Error("Parse token failed")
|
||
return nil, err
|
||
}
|
||
return
|
||
}
|
||
|
||
// 检查该token是否还有效
|
||
func (p *Token) OpVerifyValid(ctx *gin.Context, token *jwt.Token) error {
|
||
claims, ok := token.Claims.(jwt.MapClaims)
|
||
if !ok {
|
||
return fmt.Errorf("Token type assertion failed")
|
||
}
|
||
if !token.Valid {
|
||
return fmt.Errorf("Token is invalid")
|
||
}
|
||
|
||
tokenUuid, err := strconv.ParseInt(fmt.Sprintf("%.f", claims["token_uuid"]), 10, 64)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to acquire token_uuid from token")
|
||
}
|
||
|
||
list, err := p.OpList(ctx, &tokenproto.OpListReq{
|
||
Id: tokenUuid,
|
||
})
|
||
if err != nil {
|
||
return fmt.Errorf("OpList failed")
|
||
}
|
||
if len(list) == 0 {
|
||
return fmt.Errorf("登录失效,请重新登录!")
|
||
}
|
||
|
||
return nil
|
||
}
|