zoukankan      html  css  js  c++  java
  • DRF-jwt认证

    DRF-jwt认证(三大认证)

    authentication认证

    """
    系统:session认证
    rest_framework.authentication.SessionAuthentication
    ajax请求通过认证:
    cookie中要携带 sessionid、csrftoken,请求头中要携带 x-csrftoken
    
    第三方:jwt认证 
    rest_framework_jwt.authentication.JSONWebTokenAuthentication
    ajax请求通过认证:
    请求头中要携带 authorization,值为 jwt空格token
    
    自定义:基于jwt、其它
    1)自定义认证类,继承BaseAuthentication(或其子类),重写authenticate
    2)authenticate中完成
    	拿到认证标识 auth
    	反解析出用户 user
    	前两步操作失败 返回None => 游客
    	前两步操作成功 返回user,auth => 登录用户
    	注:如果在某个分支抛出异常,直接定义失败 => 非法用户
    """
    

    自定义认证类:基于jwt

    from rest_framework.exceptions import AuthenticationFailed
    import jwt
    from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
    from rest_framework_jwt.authentication import jwt_decode_handler
    
    class JWTAuthentication(BaseJSONWebTokenAuthentication):
        # 自定义认证类,重写authenticate方法
        def authenticate(self, request):
            # 认证通过,返回user,auth
            # 认证失败,返回None
            auth = request.META.get('HTTP_AUTH')  # 前台用auth携带token
            if not auth:
                return None
    
            try:
                payload = jwt_decode_handler(auth)
    
            # 出现jwt解析异常,直接抛出异常,代表非法用户,也可以返回None,作为游客处理
            except jwt.ExpiredSignature:
                raise AuthenticationFailed('token已过期')
            except:
                raise AuthenticationFailed('token非法')
    
    
            user = self.authenticate_credentials(payload)
            return (user, auth)
    

    普通自定义认证类

    from rest_framework.authentication import BaseAuthentication
    def authenticate(self, request):
        auth = 从request中得到
        user = 从auth中得到
        if not user:
            return None
        return user, auth
    

    permission权限

    """
    系统:
    1)AllowAny:允许所有用户,校验方法直接返回True
    2)IsAuthenticated:只允许登录用户
    	必须request.user和request.user.is_authenticated都通过
    3)IsAuthenticatedOrReadOnly:游客只读,登录用户无限制
    	get、option、head 请求无限制
    	前台请求必须校验 request.user和request.user.is_authenticated
    4)IsAdminUser:是否是后台用户
    	校验 request.user和request.user.is_staff    is_staff(可以登录后台管理系统的用户)
    	
    
    自定义:基于auth的Group与Permission表
    1)自定义权限类,继承BasePermission,重写has_permission
    2)has_permission中完成
    	拿到登录用户 user <= request.user
    	校验user的分组或是权限
    	前两步操作失败 返回False => 无权限
    	前两步操作成功 返回True => 有权限
    """
    

    自定义权限类:为 管理员 分组成员

    from rest_framework.permissions import BasePermission
    
    class AdminPermission(BasePermission):
        # 继承BasePermission,重写has_permission
        def has_permission(self, request, view):
            # 有权限,返回True
            # 无权限,返回False
            user = request.user
            if not user:
                return False
            # 用户是 管理员 分组 (管理员分组是Group表中的一条自定义记录)
            if not user.groups.filter(name='管理员'):
                return False
            # 登录的用户必须是自定义管理员分组成员
            return True
    

    throttle频率

    """
    系统:
    1)AnonRateThrottle:对同一IP游客的限制
    2)UserRateThrottle:对同一IP登录用户的限制
    必须在settings.py中
    'DEFAULT_THROTTLE_RATES': {
        'user': '10/min',  # 登录的用户一分钟可以访问10次
        'anon': '3/min',  # 游客一分钟可以访问3次
    }
    在视图类中:
    class TempAPIView(APIView):
    	...
    	throttle_classes = [AnonRateThrottle, UserRateThrottle]
    	
    	
    
    自定义:基于auth的Group与Permission表
    1)自定义频率类,继承SimpleRateThrottle,重写get_cache_key,明确scope
    	SimpleRateThrottle已经帮我们实现了 allow_request、wait
    2)scope与settings.py的DEFAULT_THROTTLE_RATES配合使用
    3)get_cache_key中完成
    	拿到限制信息 ident <= request中获取
    	没有限制信息 返回None => 不限制
    	有限制信息 返回限制信息字符串 => 有限制
    """
    

    自定义频率类:一分钟一个手机号只允许访问一次接口

    from rest_framework.throttling import SimpleRateThrottle
    
    class ThreeMinRateThrottle(SimpleRateThrottle):
        scope = 'sms'
        def get_cache_key(self, request, view):
            # 对手机号频率限制
            ident = request.data.get('mobile')
            if not ident:  # 为发现限制条件,返回None代表不进行频率限制
                return None
            return self.cache_format % {
                'scope': self.scope,
                'ident': ident
            }
        
        
    # settings.py  配置文件
    'DEFAULT_THROTTLE_RATES': {
        'user': '10/min',  # 登录的用户一分钟可以访问10次
        'anon': '3/min',  # 游客一分钟可以访问3次
        'sms': '1/min',
    }
    

    session认证 实现登录接口反序列化操作

    from rest_framework.views import APIView
    from django.contrib import auth
    
    # views.py
    # 登录成功后产生cookie,cookie中携带 sessionid、csrftoken
    class LoginSessionAPIView(APIView):
        # 登录要禁用认证与权限
        authentication_classes = []
        permission_classes = []
        def post(self, request, *args, **kwargs):
            username = request.data.get('username')
            password = request.data.get('password')
            if not (username and password):
                return Response('信息有误')
            # user = models.User.objects.filter(username=username).first()  # type: models.User
            # user.check_password(password)
            user = auth.authenticate(request, username=username, password=password)
            if not user:
                return Response('登录失败')
            auth.login(request, user=user)
            return Response('登录成功')
        
     
    # postman 请求头中要携带 x-csrftoken
    from rest_framework.permissions import IsAuthenticatedOrReadOnly
    from rest_framework.authentication import SessionAuthentication
    class CarModelViewSet(ModelViewSet):
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarModelSerializer
        permission_classes = [IsAuthenticatedOrReadOnly]
        authentication_classes = [SessionAuthentication]
        
        def create(self, request, *args, **kwargs):
            return super().create(request, *args, **kwargs)
    
        def destroy(self, request, *args, **kwargs):
            obj = self.get_object()
            obj.is_delete = True
            obj.save()
            return Response('删除成功')
     
    
    # urls.py
     # 游客只可以查看,登录后可以增删改
     url(r'^cars/$', views.CarModelViewSet.as_view({
          'get': 'list',
          'post': 'create'
      }))
    

    jwt认证 实现登录接口反序列化操作

    import re
    from utils.response import APIResponse
    from rest_framework_jwt.serializers import jwt_encode_handler, jwt_payload_handler
    class LoginJWTAPIView(APIView):
        authentication_classes = ()
        permission_classes = ()
        def post(self, request, *args, **kwargs):
            # username可能携带的不止是用户名,可能还是用户的其它唯一标识 手机号 邮箱
            username = request.data.get('username')
            password = request.data.get('password')
    
            # 如果username匹配上手机号正则 => 可能是手机登录
            if re.match(r'1[3-9][0-9]{9}', username):
                try:
                    # 手动通过 user 签发 jwt-token
                    user = models.User.objects.get(mobile=username)
                except:
                    return APIResponse(1, '该手机未注册')
    
            # 邮箱登录 等
    
            # 账号登录
            else:
                try:
                    # 手动通过 user 签发 jwt-token
                    user = models.User.objects.get(username=username)
                except:
                    return APIResponse(1, '该账号未注册')
    
            # 获得用户后,校验密码并签发token
            if not user.check_password(password):
                return APIResponse(1, '密码错误')
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            return APIResponse(0, 'ok', results={
                'username': user.username,
                'mobile': user.mobile,
                'token': token
            })
        
     
    # 自定义认证类 JWTAuthentication
    from rest_framework.permissions import IsAuthenticatedOrReadOnly
    from api.authentications import JWTAuthentication
    class CarV3ModelViewSet(ModelViewSet):
        authentication_classes = [JWTAuthentication]
        permission_classes = [IsAuthenticatedOrReadOnly]
        queryset = models.Car.objects.filter(is_delete=False)
        serializer_class = serializers.CarModelSerializer
        def destroy(self, request, *args, **kwargs):
            obj = self.get_object()
            obj.is_delete = True
            obj.save()
            return Response('删除成功')
        
        
    # urls.py
     # 游客只可以查看,登录后可以增删改
     url(r'^v3/cars/$', views.CarV3ModelViewSet.as_view({
          'get': 'list',
          'post': 'create'
      }))
    
  • 相关阅读:
    MySQL5.7.17解压版安装
    autocomplete初步使用
    前端面试题:驼峰体与匈牙利语法的相互转换
    前端常用正则表达式
    解决npm报错:Module build failed: TypeError: this.getResolve is not a function
    vue实现对语言的切换,结合vue-il8n。
    大量数据处理的一个思路
    不同格式矢量数据源在MapServer上发布服务后切片缓存效率对比
    CentOS7使用yum安装PostgreSQL和PostGIS
    ArcGIS消除图斑重叠错误
  • 原文地址:https://www.cnblogs.com/gaohuayan/p/11494423.html
Copyright © 2011-2022 走看看