• REST-Framework: 认证组件 | token的介绍和使用


    一 认证简介
    Django 自带一个用户认证系统,这个系统处理用户帐户、组、权限和基于 cookie 的会话.
    只有认证通过的用户才能访问指定的url地址,比如:查询课程信息,需要登录之后才能查看,没有登录,就不能查看,这时候需要用到认证组件

    Rest-Framework中的认证

    在restframework中,认证即是通过继承BaseAuthentication重构认证的类,认证的逻辑在类的authenticate方法中实现,通过判断用户传递的信息,如果认证成功返回(用户,用户Token)元组,会将用户对象封装到request里,通过request.用户可以获得用户的相关信息。

    安装

    pip install djangorestframework-jwt

    局部使用的时候, 哪个类需要加验证,就在哪个类中加上该属性:  authentication_classes = [TokenAuth, ]

    • 要注意列表中的类,必须是已经写好的用来验证的类,

    • 列表中有多个类的时候, 如果第一个类就有两个返回值, 那么后面的类将不会再继续进行, 是否进行的关键在于验证成功后返回的值是否为空, 为空则继续循环验证类, 反之则停止

     

    1. class Course(APIView):
    2. authentication_classes = [TokenAuth, ]
    3. def get(self, request):
    4. return HttpResponse('get')
    5. def post(self, request):
    6. return HttpResponse('post')

    三 认证组件全局使用

    全局使用的时候会导致一个尴尬的问题就是我们写的登录CBV也需要登录认证才行

    全局使用的时候,我们实现部分CBV禁用的方式是,在需要的CBV中写上:authentication_classes = [ ]

    当我们写了authentication_classes = [ ] 为空的时候,将不会有返回值,就会让我们进行正常登录
     

    1. REST_FRAMEWORK = {
    2. #异常处理
    3. 'EXCEPTION_HANLER':'mall.utils.exceptions.exception_handler',
    4. 'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类
    5. 'rest_framework.renderers.JSONRenderer', # json渲染器
    6. 'rest_framework.renderers.BrowsableAPIRenderer', # 浏览API渲染器
    7. ),
    8. 'DEFAULT_AUTHENTICATION_CLASSES': (
    9. # 这里是全局的 return [auth() for auth in self.authentication_classes]
    10. # 加上后 所有接口都500
    11. 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', #token
    12. 'rest_framework.authentication.BasicAuthentication', # 基本认证
    13. 'rest_framework.authentication.SessionAuthentication', # session认证
    14. ),
    15. }
    16. JWT_AUTH = {
    17. 'JWT_EXPIRATION_DELTA': datetime.timedelta(days=2), # 指明token的有效期
    18. 'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.jwt_response_payload_hanler',
    19. }
    • JWT_EXPIRATION_DELTA 指明token的有效期
    1. # -*- coding: utf-8 -*-
    2. def jwt_response_payload_hanler(token, user=None, request=None):
    3. """自定义jwt认证返回数据"""
    4. data = {"id": user.id,"username": user.username,"mobile": user.mobile,"token":token}
    5. return data

     

    使用

    Django REST framework JWT 扩展的说明文档中提供了手动签发JWT的方法

    1. from rest_framework_jwt.settings import api_settings
    2. jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    3. jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
    4. payload = jwt_payload_handler(user)
    5. token = jwt_encode_handler(payload)

    在注册成功后,连同返回token,需要在注册视图中创建token。

    修改CreateUserSerializer序列化器,在create方法中增加手动创建token的方法

    1. # -*- coding: utf-8 -*-
    2. import re
    3. from rest_framework import serializers
    4. from users.models import User
    5. class CreateUserSerializer(serializers.ModelSerializer):
    6. password2 = serializers.CharField(label="确认密码",write_only=True)
    7. sms_code = serializers.CharField(label="短信验证码",write_only=True)
    8. allow = serializers.CharField(label="同意协议",write_only=True)
    9. token = serializers.CharField(label="登录状态token",read_only=True)
    10. class Meta:
    11. model = User
    12. fields = ("id","username","password","password2","sms_code","mobile","allow","token")
    13. extra_kwargs = {
    14. "username":{
    15. "min_length":5,
    16. "max_length":20,
    17. "error_messages":{
    18. "min_length":"仅允许5-20字符的用户名",
    19. "max_length":"仅允许5-20字符的用户名",
    20. }
    21. },
    22. "password": {
    23. "write_only": True,
    24. "min_length": 8,
    25. "max_length": 20,
    26. "error_messages": {
    27. "min_length": "仅允许8-20个字符的密码",
    28. "max_length": "仅允许8-20个字符的密码",
    29. }
    30. }
    31. }
    32. def validated_mobile(self,value):
    33. print(value)
    34. # 校验 手机号
    35. if not re.match(r'^1[3-9]\d{9}',value):
    36. raise serializers.ValidationError("手机号码格式错误")
    37. return value
    38. def validated_allow(self,value):
    39. # 校验是否同意协议
    40. if value != "true":
    41. raise serializers.ValidationError("请您勾选用户协议")
    42. return value
    43. def validate(self, data):
    44. # 判断两次密码
    45. if data['password'] != data['password2']:
    46. raise serializers.ValidationError("两次输入的密码不一致")
    47. # # 判断短信验证码
    48. # mobile = data['mobile']
    49. # redis_conn = get_redis_connection('verify_codes')
    50. # real_sms_code = redis_conn.get("sms_%s" % mobile) # 二进制
    51. # if real_sms_code is None:
    52. # raise serializers.ValidationError("无效的短信验证码")
    53. # if data['sms_code'] != real_sms_code.decode():
    54. # raise serializers.ValidationError("短信验证码错误")
    55. return data
    56. def create(self, validated_data):
    57. # 创建新用户
    58. # 移除数据库用户表里没有的字段
    59. del validated_data['password2']
    60. del validated_data['sms_code']
    61. del validated_data['allow']
    62. # user = User.objects.create(**validated_data)
    63. user = super().create(validated_data)
    64. user.set_password(validated_data['password']) #继承的一个加密密码的方法
    65. user.save()
    66. # 加上 token
    67. from rest_framework_jwt.settings import api_settings
    68. payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    69. encode_handler = api_settings.JWT_ENCODE_HANDLER
    70. payload = payload_handler(user)
    71. token = encode_handler(payload)
    72. user.token = token
    73. return user

     注意上面是全局

    认证组件全局使用
    全局使用的时候会导致一个尴尬的问题就是我们写的登录CBV也需要登录认证才行

    全局使用的时候,我们实现部分CBV禁用的方式是,在需要的CBV中写上:authentication_classes = [ ]

    当我们写了authentication_classes = [ ] 为空的时候,将不会有返回值,就会让我们进行正常登录
     

    注册/验证手机号不需要token

    1. import random
    2. from django.http import HttpResponse
    3. from rest_framework.views import APIView
    4. from rest_framework.generics import GenericAPIView
    5. from verifications.serializers import ImageCodeCheckSerializer
    6. from rest_framework.response import Response
    7. # Create your views here.
    8. from libs.captcha.captcha import captcha
    9. from libs.aliyunsms.sms_send import send_sms_code
    10. '''
    11. 图片验证
    12. 1.第三方插件 captcha
    13. '''
    14. class ImageCodeView(APIView):
    15. authentication_classes = []
    16. # 图片验证码
    17. def get(self,request,image_code_id):
    18. # 获取图片的验证码
    19. # 1.调用图片模块 接收图片验证码和图片对象
    20. text,image = captcha.generate_captcha()
    21. print(text)
    22. # 2.保存这个图片验证码的真实值 redis
    23. #redis_conn = get_redis_connection('verify_codes')
    24. # redis_conn.setex("img_%s" % image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
    25. # 保存到session
    26. request.session['info'] = text
    27. # 获取 request.session.info
    28. print(request.session.get("info"))
    29. return HttpResponse(image,content_type="image/png")
    30. # GET /sms_codes/(P1[3-9]\d{9})/?text=1234&image_code_id=uuid
    31. class SMSCodeView(GenericAPIView):
    32. authentication_classes = []
    33. serializer_class = ImageCodeCheckSerializer
    34. # 发送短信验证码
    35. def get(self,request,mobile):
    36. # 1.校验参数 由序列化器完成
    37. serializer = self.get_serializer(data=request.query_params)
    38. serializer.is_valid(raise_exception=True)
    39. # 2.发送短信需生成一个随机的验证码
    40. sms_code = "%06d" % random.randint(0,999999)
    41. print("短信验证码: %s" % sms_code)
    42. # 3.保存短信验证码
    43. request.session['sms_code'] = sms_code
    44. # 4.发送短信
    45. send_sms_code(mobile,sms_code)
    46. return Response({"message":"ok"})
    47. # 给这个发送短信的接口做限流 一天最或发5次。

    总结:局部使用,只需要在视图类里加入:

    authentication_classes = [TokenAuth, ]

  • 相关阅读:
    在 NPM 中设置代理
    ELF文件格式解析
    合同管理系统
    C++ 34 之 单例模式
    项目进度网络图
    ubuntu 校验 .desktop文件
    3D目标检测进展综述(论文笔记)
    进行基于fluent的山地风场仿真模拟与深度学习卷积神经网络结合的流场预测与误差评估
    C++哈希(位图,布隆过滤器,哈希切分)
    C语言入门(一)常量、变量
  • 原文地址:https://blog.csdn.net/weixin_38107457/article/details/126320048