34.django使用jwt

1.jwt

这里是打包的代码地址jwt代码包

json web token:用于用户认证(前后端分离/微信小程序/app开发)
- 基于传统的token认证
	用户登录,服务端给返回token,并将token(服务端不保存)
    以后用户再来访问时,需要携带token,服务端获取token后,再去数据库中获取token
- jwt
	用户登陆之后,服务端给用户返回一个token(服务器不保存)
    以后用户访问,都需要带着token,服务器获取token后,通过算法进行token验证

优势:相较于传统的token相比,他无需在服务端保存token

2.jwt实现过程

1.提交用户名和密码给服务端,如果登录成功,使用jwt生成一个token值,并返回给用户

注意:jwt生成的token是由三段字符串通过.连接起来的

第一段字符串:HEADER,内部包含算法token类型。
json转化成字符串,然后做base64url加密(base64加密;+-\)
{
    "alg": "HS256",
    'type': "JWT"
}
第二段字符串:payload,自定义值:
json转化成字符串,然后做base64url加密(base64加密;+-\)
{
    'id': "124124",
    'name':'chengge',
    'exp': '1423434132',# 超时时间
}
第三段字符串:
第一步:将第1,2不封密文拼接起来
第二步:对前两部分密文进行hs256加密+加盐
第三步:对hs256加密后的密文在做base64url加密

- 以后用户来访问时候,携带token,后端需要对token进行校验
	- 获取token
    - 第一步:对token进行切割
    - 第二步:把第二段进行base64解密,并获取payload信息,检测超市时间
 	- 第二步:把第一个段拼接再次执行hs256加密+加盐
    
    密文 = base64解密
    如果密文相等表示token没有被修改过

3.应用

pip install pyjwt
pyjwt.encode 生成token
pyjwt.decode token解密

4.扩展

pip install djagnrestframework-jwt
djagnrestframework-jwt 本质上是调用pyjwt实现的

版本一:

原理就是服务端保存tokne

class LoginView(APIView):
    '''用户登录'''
    def post(self, request, *args, **kwargs):
        username = request.data.get("username")
        passwork = request.data.get("password")
        user_obj = models.UserInfo.objects.filter(username=username, password=passwork).first()
        if not user_obj:
            return Response({"code": 1000, 'error': '用户名或密码错误'})
        random_string = str(uuid.uuid4())
        user_obj.token = random_string
        user_obj.save()
        return Response({"code":1001, 'data': '登陆成功'})


class OrderView(APIView):
    def get(self, request, *args, **kwargs):
        token = request.query_params.get("token")
        print(token)
        if not token:
            Response({"code": 1003, 'error': '未登录失败'})
        user_obj = models.UserInfo.objects.filter(token=token).exists()
        if not user_obj:
            Response({"code": 1003, 'error': '未登录失败'})
        return Response("订单列表")

版本二:

通过jwt进行验证,但是发现每个函数都要使用太麻烦了

class JwtLoginView(APIView):
    '''用户登录'''
    def post(self, request, *args, **kwargs):
        username = request.data.get("username")
        passwork = request.data.get("password")
        user_obj = models.UserInfo.objects.filter(username=username, password=passwork).exists()
        if not user_obj:
            return Response({"code": 1000, 'error': '用户名或密码错误'})


        import jwt
        import datetime
        salt = "fadsf$@%#%#%gsfdgsdgfd"
        headers = {
            "typ": "jwt_",
            "alg": "HS256",
        }
        payload = {
            "user_id": 1,
            "username": "alex",
            "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=1)
        }

        token = jwt.encode(payload=payload, key=salt, headers=headers).decode("utf-8")
        return Response({"code":1001, 'data': token})


class JwtOrderView(APIView):
    def get(self, request, *args, **kwargs):
        # 获取token并验证
        token = request.query_params.get("token")
        import jwt
        from jwt import exceptions
        result = None
        msg = None
        salt = "fadsf$@%#%#%gsfdgsdgfd"
        try:
            result = jwt.decode(token, salt, True)
        except exceptions.ExpiredSignatureError:
            msg = "token失效"

        except exceptions.DecodeError:
            msg = "token认证失败"
        except exceptions.InvalidTokenError:
            msg = "非法token"

        if not result:
            return Response({"code": 1002, "msg": msg})

        return Response("订单列表")

版本三:

使用restful的认证组件认证

class PrLoginView(APIView):
    authentication_classes = []

    def post(self, request, *args, **kwargs):
        username = request.data.get("username")
        passwork = request.data.get("password")
        user_obj = models.UserInfo.objects.filter(username=username, password=passwork).first()
        if not user_obj:
            return Response({"code": 1000, 'error': '用户名或密码错误'})
        payload = {
            "id": user_obj.pk,
            "name": user_obj.username,
        }
        token = get_token(payload, 5)
        return Response({"code": 1001, 'data': token})


class PrOrderView(APIView):

    # authentication_classes = [JwtQuertParamsAuthentication]

    def get(self, request, *args, **kwargs):

        return Response("订单列表")
# get_token函数
import jwt
import datetime
from django.conf import settings
def get_token(payload, timeout):
    salt = settings.SECRET_KEY
    headers = {
        "typ": "jwt_",
        "alg": "HS256",
    }
    payload["exp"] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)
    token = jwt.encode(payload=payload, key=salt, headers=headers).decode("utf-8")
    return token

实现一个restframework的认证类,将它应用到视图函数之中就可以了

import jwt
from jwt import exceptions
from rest_framework.authentication import BaseAuthentication
from django.conf import settings
from rest_framework.exceptions import AuthenticationFailed
class JwtQuertParamsAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token = request.query_params.get("token")
        salt = settings.SECRET_KEY
        try:
            result = jwt.decode(token, salt, True)
        except exceptions.ExpiredSignatureError:
            msg = "token失效"
            raise AuthenticationFailed({"code": 1001, "msg": msg})
        except exceptions.DecodeError:
            msg = "token认证失败"
            raise AuthenticationFailed({"code": 1002, "msg": msg})

        except exceptions.InvalidTokenError:
            msg = "非法token"
            raise AuthenticationFailed({"code": 1003, "msg": msg})

        return (result, token)

        # 三种操作
        # 1.抛出错误,后续不再执行
        # 2.return一个元组,(1,2)认证通过,在视图中如果调用request.user 就是第一个值request.auth就是第二个
        # 3.None不做任何操作
posted @ 2020-04-12 17:08  楠海  阅读(3602)  评论(0编辑  收藏  举报