前后端分离项目中经常使用用户验证,为什么要使用验证,因为http是无状态 的,无法辨别是否正确,早起的cookie、session、token,以及现在说的jwt认证
jwt和token类似,最大的区别是token要保存在服务端造成后端存储压力增大,因此使用jwt
在django中使用jwt认证
创建django项目
导入相关依赖
具体代码一下
extensions文件夹下创建一个auth.py文件
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from utils.jwt_auth import parse_payload
class JwtQueryParamAuthentication(BaseAuthentication):
"""
用户需要在url中通过参数进行传输token,例如:
http://www.pythonav.com?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzM1NTU1NzksInVzZXJuYW1lIjoid3VwZWlxaSIsInVzZXJfaWQiOjF9.xj-7qSts6Yg5Ui55-aUOHJS4KSaeLq5weXMui2IIEJU
"""
def authenticate(self, request):
token = request.query_params.get('token')
payload = parse_payload(token)
if not payload['status']:
raise exceptions.AuthenticationFailed(payload)
# 如果想要request.user等于用户对象,此处可以根据payload去数据库中获取用户对象。
return (payload, token)
class JwtAuthorizationAuthentication(BaseAuthentication):
"""
用户需要通过请求头的方式来进行传输token,例如:
Authorization:jwt eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzM1NTU1NzksInVzZXJuYW1lIjoid3VwZWlxaSIsInVzZXJfaWQiOjF9.xj-7qSts6Yg5Ui55-aUOHJS4KSaeLq5weXMui2IIEJU
"""
def authenticate(self, request):
# 非登录页面需要校验token
authorization = request.META.get('HTTP_AUTHORIZATION', '')
auth = authorization.split()
if not auth:
raise exceptions.AuthenticationFailed({'error': '未获取到Authorization请求头', 'status': False})
if auth[0].lower() != 'jwt':
raise exceptions.AuthenticationFailed({'error': 'Authorization请求头中认证方式错误', 'status': False})
if len(auth) == 1:
raise exceptions.AuthenticationFailed({'error': "非法Authorization请求头", 'status': False})
elif len(auth) > 2:
raise exceptions.AuthenticationFailed({'error': "非法Authorization请求头", 'status': False})
token = auth[1]
result = parse_payload(token)
if not result['status']:
raise exceptions.AuthenticationFailed(result)
# 如果想要request.user等于用户对象,此处可以根据payload去数据库中获取用户对象。
return (result, token)
在utils中创建一个jet_auth.py文件
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import jwt
import datetime
from jwt import exceptions
JWT_SALT = 'iv%x6xo7l7_u9bf_u!9#g#m*)*=ej@bek5)(@u3kh*72+unjv='
def create_token(payload, timeout=20):
"""
:param payload: 例如:{'user_id':1,'username':'wupeiqi'}用户信息
:param timeout: token的过期时间,默认20分钟
:return:
"""
headers = {
'typ': 'jwt',
'alg': 'HS256'
}
payload['exp'] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)
result = jwt.encode(payload=payload, key=JWT_SALT, algorithm="HS256", headers=headers).decode('utf-8')
return result
def parse_payload(token):
"""
对token进行和发行校验并获取payload
:param token:
:return:
"""
result = {'status': False, 'data': None, 'error': None}
try:
verified_payload = jwt.decode(token, JWT_SALT, True)
result['status'] = True
result['data'] = verified_payload
except exceptions.ExpiredSignatureError:
result['error'] = 'token已失效'
except jwt.DecodeError:
result['error'] = 'token认证失败'
except jwt.InvalidTokenError:
result['error'] = '非法的token'
return result
在视图中直接使用token
token = create_token({'username': 'wupeiqi'})
前端请求过来的时候使用jwt进行验证
在视图中加入
authentication_classes = [JwtQueryParamAuthentication, ]
全局所有的类视图都使用jwt进行验证
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['extensions.auth.JwtQueryParamAuthentication']
}
例如说登录类上面不需要进行验证
authentication_classes = []