mirror of
				https://github.com/openimsdk/open-im-server.git
				synced 2025-10-31 16:32:12 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			232 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package token_verify
 | |
| 
 | |
| import (
 | |
| 	"Open_IM/pkg/common/config"
 | |
| 	"Open_IM/pkg/common/constant"
 | |
| 	commonDB "Open_IM/pkg/common/db"
 | |
| 	"Open_IM/pkg/common/log"
 | |
| 	"Open_IM/pkg/utils"
 | |
| 	"github.com/garyburd/redigo/redis"
 | |
| 	"github.com/golang-jwt/jwt/v4"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| //var (
 | |
| //	TokenExpired     = errors.New("token is timed out, please log in again")
 | |
| //	TokenInvalid     = errors.New("token has been invalidated")
 | |
| //	TokenNotValidYet = errors.New("token not active yet")
 | |
| //	TokenMalformed   = errors.New("that's not even a token")
 | |
| //	TokenUnknown     = errors.New("couldn't handle this token")
 | |
| //)
 | |
| 
 | |
| type Claims struct {
 | |
| 	UID      string
 | |
| 	Platform string //login platform
 | |
| 	jwt.RegisteredClaims
 | |
| }
 | |
| 
 | |
| func BuildClaims(uid, platform string, ttl int64) Claims {
 | |
| 	now := time.Now()
 | |
| 	return Claims{
 | |
| 		UID:      uid,
 | |
| 		Platform: platform,
 | |
| 		RegisteredClaims: jwt.RegisteredClaims{
 | |
| 			ExpiresAt: jwt.NewNumericDate(now.Add(time.Duration(ttl*24) * time.Hour)), //Expiration time
 | |
| 			IssuedAt:  jwt.NewNumericDate(now),                                        //Issuing time
 | |
| 			NotBefore: jwt.NewNumericDate(now),                                        //Begin Effective time
 | |
| 		}}
 | |
| }
 | |
| 
 | |
| func CreateToken(userID string, platformID int32) (string, int64, error) {
 | |
| 	claims := BuildClaims(userID, constant.PlatformIDToName(platformID), config.Config.TokenPolicy.AccessExpire)
 | |
| 	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
 | |
| 	tokenString, err := token.SignedString([]byte(config.Config.TokenPolicy.AccessSecret))
 | |
| 	if err != nil {
 | |
| 		return "", 0, err
 | |
| 	}
 | |
| 	//remove Invalid token
 | |
| 	m, err := commonDB.DB.GetTokenMapByUidPid(userID, constant.PlatformIDToName(platformID))
 | |
| 	if err != nil && err != redis.ErrNil {
 | |
| 		return "", 0, err
 | |
| 	}
 | |
| 	var deleteTokenKey []string
 | |
| 	for k, v := range m {
 | |
| 		_, err = GetClaimFromToken(k)
 | |
| 		if err != nil || v != constant.NormalToken {
 | |
| 			deleteTokenKey = append(deleteTokenKey, k)
 | |
| 		}
 | |
| 	}
 | |
| 	if len(deleteTokenKey) != 0 {
 | |
| 		err = commonDB.DB.DeleteTokenByUidPid(userID, platformID, deleteTokenKey)
 | |
| 		if err != nil {
 | |
| 			return "", 0, err
 | |
| 		}
 | |
| 	}
 | |
| 	err = commonDB.DB.AddTokenFlag(userID, platformID, tokenString, constant.NormalToken)
 | |
| 	if err != nil {
 | |
| 		return "", 0, err
 | |
| 	}
 | |
| 	return tokenString, claims.ExpiresAt.Time.Unix(), err
 | |
| }
 | |
| 
 | |
| func secret() jwt.Keyfunc {
 | |
| 	return func(token *jwt.Token) (interface{}, error) {
 | |
| 		return []byte(config.Config.TokenPolicy.AccessSecret), nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func GetClaimFromToken(tokensString string) (*Claims, error) {
 | |
| 	token, err := jwt.ParseWithClaims(tokensString, &Claims{}, secret())
 | |
| 	if err != nil {
 | |
| 		if ve, ok := err.(*jwt.ValidationError); ok {
 | |
| 			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
 | |
| 				return nil, &constant.ErrTokenMalformed
 | |
| 			} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
 | |
| 				return nil, &constant.ErrTokenExpired
 | |
| 			} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
 | |
| 				return nil, &constant.ErrTokenNotValidYet
 | |
| 			} else {
 | |
| 				return nil, &constant.ErrTokenUnknown
 | |
| 			}
 | |
| 		} else {
 | |
| 			return nil, &constant.ErrTokenNotValidYet
 | |
| 		}
 | |
| 	} else {
 | |
| 		if claims, ok := token.Claims.(*Claims); ok && token.Valid {
 | |
| 			//log.NewDebug("", claims.UID, claims.Platform)
 | |
| 			return claims, nil
 | |
| 		}
 | |
| 		return nil, &constant.ErrTokenNotValidYet
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func IsAppManagerAccess(token string, OpUserID string) bool {
 | |
| 	claims, err := ParseToken(token, "")
 | |
| 	if err != nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	if utils.IsContain(claims.UID, config.Config.Manager.AppManagerUid) && claims.UID == OpUserID {
 | |
| 		return true
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func IsManagerUserID(OpUserID string) bool {
 | |
| 	if utils.IsContain(OpUserID, config.Config.Manager.AppManagerUid) {
 | |
| 		return true
 | |
| 	} else {
 | |
| 		return false
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func CheckAccess(OpUserID string, OwnerUserID string) bool {
 | |
| 	if utils.IsContain(OpUserID, config.Config.Manager.AppManagerUid) {
 | |
| 		return true
 | |
| 	}
 | |
| 	if OpUserID == OwnerUserID {
 | |
| 		return true
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func GetUserIDFromToken(token string, operationID string) (bool, string) {
 | |
| 	claims, err := ParseToken(token, operationID)
 | |
| 	if err != nil {
 | |
| 		log.Error(operationID, "ParseToken failed, ", err.Error(), token)
 | |
| 		return false, ""
 | |
| 	}
 | |
| 	return true, claims.UID
 | |
| }
 | |
| 
 | |
| func ParseTokenGetUserID(token string, operationID string) (error, string) {
 | |
| 	claims, err := ParseToken(token, operationID)
 | |
| 	if err != nil {
 | |
| 		return utils.Wrap(err, ""), ""
 | |
| 	}
 | |
| 	return nil, claims.UID
 | |
| }
 | |
| 
 | |
| func ParseToken(tokensString, operationID string) (claims *Claims, err error) {
 | |
| 	claims, err = GetClaimFromToken(tokensString)
 | |
| 	if err != nil {
 | |
| 		log.NewError(operationID, "token validate err", err.Error(), tokensString)
 | |
| 		return nil, utils.Wrap(err, "")
 | |
| 	}
 | |
| 
 | |
| 	m, err := commonDB.DB.GetTokenMapByUidPid(claims.UID, claims.Platform)
 | |
| 	if err != nil {
 | |
| 		log.NewError(operationID, "get token from redis err", err.Error(), tokensString)
 | |
| 		return nil, utils.Wrap(&constant.ErrTokenInvalid, "get token from redis err")
 | |
| 	}
 | |
| 	if m == nil {
 | |
| 		log.NewError(operationID, "get token from redis err", "m is nil", tokensString)
 | |
| 		return nil, utils.Wrap(&constant.ErrTokenInvalid, "get token from redis err")
 | |
| 	}
 | |
| 	if v, ok := m[tokensString]; ok {
 | |
| 		switch v {
 | |
| 		case constant.NormalToken:
 | |
| 			log.NewDebug(operationID, "this is normal return", claims)
 | |
| 			return claims, nil
 | |
| 		case constant.InValidToken:
 | |
| 			return nil, utils.Wrap(&constant.ErrTokenInvalid, "")
 | |
| 		case constant.KickedToken:
 | |
| 			log.Error(operationID, "this token has been kicked by other same terminal ", constant.ErrTokenKicked)
 | |
| 			return nil, utils.Wrap(&constant.ErrTokenKicked, "this token has been kicked by other same terminal ")
 | |
| 		case constant.ExpiredToken:
 | |
| 			return nil, utils.Wrap(&constant.ErrTokenExpired, "")
 | |
| 		default:
 | |
| 			return nil, utils.Wrap(&constant.ErrTokenUnknown, "")
 | |
| 		}
 | |
| 	}
 | |
| 	log.NewError(operationID, "redis token map not find", constant.ErrTokenUnknown)
 | |
| 	return nil, utils.Wrap(&constant.ErrTokenUnknown, "redis token map not find")
 | |
| }
 | |
| 
 | |
| //func MakeTheTokenInvalid(currentClaims *Claims, platformClass string) (bool, error) {
 | |
| //	storedRedisTokenInterface, err := db.DB.GetPlatformToken(currentClaims.UID, platformClass)
 | |
| //	if err != nil {
 | |
| //		return false, err
 | |
| //	}
 | |
| //	storedRedisPlatformClaims, err := ParseRedisInterfaceToken(storedRedisTokenInterface)
 | |
| //	if err != nil {
 | |
| //		return false, err
 | |
| //	}
 | |
| //	//if issue time less than redis token then make this token invalid
 | |
| //	if currentClaims.IssuedAt.Time.Unix() < storedRedisPlatformClaims.IssuedAt.Time.Unix() {
 | |
| //		return true, constant.TokenInvalid
 | |
| //	}
 | |
| //	return false, nil
 | |
| //}
 | |
| 
 | |
| func ParseRedisInterfaceToken(redisToken interface{}) (*Claims, error) {
 | |
| 	return GetClaimFromToken(string(redisToken.([]uint8)))
 | |
| }
 | |
| 
 | |
| //Validation token, false means failure, true means successful verification
 | |
| func VerifyToken(token, uid string) (bool, error) {
 | |
| 	claims, err := ParseToken(token, "")
 | |
| 	if err != nil {
 | |
| 		return false, err
 | |
| 	}
 | |
| 	if claims.UID != uid {
 | |
| 		return false, &constant.ErrTokenUnknown
 | |
| 	}
 | |
| 
 | |
| 	log.NewDebug("", claims.UID, claims.Platform)
 | |
| 	return true, nil
 | |
| }
 | |
| func WsVerifyToken(token, uid string, platformID string) (bool, error, string) {
 | |
| 	claims, err := ParseToken(token, "")
 | |
| 	if err != nil {
 | |
| 		return false, utils.Wrap(err, "parse token err"), "parse token err"
 | |
| 	}
 | |
| 	if claims.UID != uid {
 | |
| 		return false, utils.Wrap(&constant.ErrTokenUnknown, "uid is not same to token uid"), "uid is not same to token uid"
 | |
| 	}
 | |
| 	if claims.Platform != constant.PlatformIDToName(utils.StringToInt32(platformID)) {
 | |
| 		return false, utils.Wrap(&constant.ErrTokenUnknown, "platform is not same to token platform"), "platform is not same to token platform"
 | |
| 	}
 | |
| 	log.NewDebug("", claims.UID, claims.Platform)
 | |
| 	return true, nil, ""
 | |
| }
 |