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
}