jwt在go和python中的用法比较和统一

jwt的token都是放在http的header中的Authorization,格式为"jwt xxxxxx"

jwt在python中的使用

web框架是flask,参考Flask_JWT的实现,这里重写了一下,为的是用的更灵活些

# decorator.py
import jwt

current_identity = LocalProxy(lambda: getattr(_request_ctx_stack.top, 'current_identity', None))

def jwt_payload(identity):
    iat = datetime.utcnow()
    exp = iat + current_app.config.get('JWT_EXPIRATION_DELTA')
    return {'exp': exp, 'iat': iat, 'identity': identity }


def jwt_encode(identity):
    secret = current_app.config['JWT_SECRET_KEY']
    algorithm = current_app.config['JWT_ALGORITHM']
    required_claims = current_app.config['JWT_REQUIRED_CLAIMS']

    payload = jwt_payload(identity)
    missing_claims = list(set(required_claims) - set(payload.keys()))

    if missing_claims:
        raise RuntimeError('Payload is missing required claims: %s' % ', '.join(missing_claims))

    return jwt.encode(payload, secret, algorithm=algorithm, headers=None)


def jwt_decode(token):
    secret = current_app.config['JWT_SECRET_KEY']
    algorithm = current_app.config['JWT_ALGORITHM']
    leeway = current_app.config['JWT_LEEWAY']

    verify_claims = current_app.config['JWT_VERIFY_CLAIMS']
    required_claims = current_app.config['JWT_REQUIRED_CLAIMS']

    options = {
        'verify_' + claim: True
        for claim in verify_claims
    }

    options.update({
        'require_' + claim: True
        for claim in required_claims
    })

    return jwt.decode(token, secret, options=options, algorithms=[algorithm], leeway=leeway)


def jwt_required(fn):
    @wraps(fn)
    def wapper(*args, **kwargs):
        auth_header_value = request.headers.get('Authorization', None)
        if not auth_header_value:
            raise LoginError(message = 'Authorization缺失!')

        parts = auth_header_value.split()
        if len(parts) == 1:
            raise LoginError(message = 'Token缺失!')

        elif len(parts) > 2:
            raise LoginError(message = 'Token无效!')

        token = parts[1]
        if token is None:
            raise LoginError(message = 'Token异常!')

        try:
            payload = jwt_decode(token)
        except jwt.InvalidTokenError as e:
            raise LoginError(message="Token失效")

        _request_ctx_stack.top.current_identity = payload.get('identity')

        if payload.get('identity') is None:
            raise LoginError(message = '用户不存在!')

        return fn(*args, **kwargs)
    return wapper

登陆成功通过jwt_encode生成token

@api.route('/login', methods=["POST"])
def login():
	......
	token = jwt_encode({ 'user_id': "xxx", 'user_name': "xxx"})
	return {'token': token.decode('utf8')}

通过装饰器添加jwt校验

@api.route('/modify', methods=['POST'])
@jwt_required
def user_modify():
	user_id = current_identity.get('user_id')
	......

jwt在go中的应用

web框架用的是gin

// jwt.go
import (
	"fmt"
	"strings"
	"net/http"
	"go-server/utils"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

var (
	JWT_KEY               = []byte("demodemodeomdemo")
	JWT_EXPIRE_TIME int64 = 3600 * 24
)

type PayLoad struct {
	UserID   int    `json:"user_id"`
	UserName string `json:"user_name"`
	Avatar   string `json:"avatar"`
	RoleID   int    `json:"role_id"`
	GroupID  int    `json:"group_id"`
}

type CustomClaims struct {
	Identity PayLoad `json:"identity"`
	jwt.StandardClaims
}

func JwtAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		tokenString := c.Request.Header.Get("Authorization")
		if tokenString == "" {
			c.Abort()
			c.JSON(http.StatusOK, utils.RespJson(utils.LOGINERR, "login error", nil))
			return
		}
		t := strings.Split(tokenString, " ")
		if len(t) < 2{
			c.Abort()
			c.JSON(http.StatusOK, utils.RespJson(utils.LOGINERR, "token error", nil))
			return
		}
		token, err := jwt.ParseWithClaims(t[1], &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
			return JWT_KEY, nil
		})
		if err != nil {
			if ve, ok := err.(*jwt.ValidationError); ok {
				if ve.Errors&jwt.ValidationErrorMalformed != 0 {
					fmt.Println("That's not even a token")
				} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
					fmt.Println("Token is expired")
				} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
					fmt.Println("Token not active yet")
				} else {
					fmt.Println("Couldn't handle this token")
				}
				c.Abort()
				c.JSON(http.StatusOK, utils.RespJson(utils.LOGINERR, "login error", nil))
				return
			}
		}
		claims, ok := token.Claims.(*CustomClaims)
		if !ok || !token.Valid {
			c.Abort()
			fmt.Println("token is invalid")
			c.JSON(http.StatusOK, utils.RespJson(utils.LOGINERR, "login error", nil))
			return
		}
		
		c.Set("claims", gin.H{
						"user_name":   claims.Identity.UserName,
						"user_id":     claims.Identity.UserID,
						"avatar":      claims.Identity.Avatar,
						"role_id":      claims.Identity.RoleID,
						"current_url": c.Request.URL.Path})
		c.Next()
	}
}

路由上添加jwt验证

//router.go
func InitRouter(router *gin.Engine) *gin.Engine {
	router.POST("/login", Login)
	router.POST("/logout", middleware.JwtAuth(), Logout)
	router.POST("/regist", Regist)
	apiAccount := router.Group("/account").Use(middleware.JwtAuth())
	{
		apiAccount.POST("/modify", AccountModify)
		apiAccount.GET("/list", AccountList)
	}
}

从jwt中取用户相关信息

// xx_handler.go
func xxx(c *gin.Context) {
	var currentUser gin.H
		if tmp, ok := c.Get("claims"); ok {
			if claims, ok := tmp.(gin.H); ok {
				currentUser = claims
			}
		}
	var userID = currentUser["user_id"].(int)
	......

登陆成功后生成token

func Login(c *gin.Context) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, middleware.CustomClaims{
			middleware.PayLoad{UserID:u.ID, UserName:u.Name, Avatar:u.Avatar, RoleID:u.RoleID, GroupID:u.GroupID},
			jwt.StandardClaims{ExpiresAt: int64(time.Now().Unix() + middleware.JWT_EXPIRE_TIME), Issuer:"go-server"},
		})
	tokenString, err := token.SignedString([]byte(middleware.JWT_KEY))
	if err != nil {
		c.JSON(http.StatusOK, utils.RespJson(utils.PARAMERR, "登录失败,请重试!", nil))
		return
	}
	c.JSON(http.StatusOK, utils.RespJson(utils.REQOK, "ok", gin.H{"token": tokenString}))
	return
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值