三大认证

Posted mqhpy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三大认证相关的知识,希望对你有一定的参考价值。

1、重点知识点概况

'''
1、三大认证:
    认证组件:request.user登录用户
    权限组件:user是否有权限
    频率组件:3/min一分钟可以访问三次
    
2、auth认证六表:user、group、permission,加上这三个关系表

3、自定义user表
    1)自定义User继承AbstractUser
    2)在settings中配置AUTH_USER_MODEL
    3)admin注册自定义User表,配置UserAdmin
    
4、认证规则:session认证、jwt认证
    jwt认证:json web token;只有客户端存token;服务端只负责token的签发与校验
    jwt:header.payload.sign(头-基本信息.荷载-核心信息.签名-安全信息)
   
5、drf-jwt:
    签发token、校验token、刷新token的三个视图类
    认证组件(校验jwt token,得到登录用户user,存储到request.user中)
    
6、sessions中配置
    # drf框架自定义配置
    REST_FRAMEWORK = {
        # 异常模块:异常处理函数
        'EXCEPTION_HANDLER': 'api.exception.exception_handler',
        
        # 认证组件
        'DEFAULT_AUTHENTICATION_CLASSES': [
            # 'rest_framework.authentication.SessionAuthentication',
            # 'rest_framework.authentication.BasicAuthentication'
            'rest_framework_jwt.authentication.JSONWebTokenAuthentication'
        ],

        # 频率组件:频率类一般做局部配置,但是频率调节在settings中配置
        'DEFAULT_THROTTLE_RATES': {
            'user': '5/min',
            'anon': '3/min',
            'mobile': '1/min'
        },
    }
'''

2、认证组件

#1、使用jwt认证组件(基本满足工作需求)
#认证组件在sessions文件全局配置drf-jwt框架的认证类
REST_FRAMEWORK = {
    # 全局认证组件(基本满足工作需求)
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication'
    ],
}


#2、若你的功能较多,要求较多,也可以采用自定义认证(建议:建一个py文件专门存放你的自定义代码,好处大大的,谁用谁知道!)
#在视图类中导入我们写的自定义认证
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

# 自定义认证类
# 1) 如果使用session认证,drf默认提供了SessionAuthentication
# 2) 如果使用drf-jwt认证框架,drf-jwt框架提供了JSONWebTokenAuthentication
# 3) 如果是自定义签发与校验token,才需要将校验token的算法封装到自定义的认证类中
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        """
        1) 从请求头中拿到前台提交的token(一般从HTTP_AUTHORIZATION中拿,也可以与前台约定)
              -- 如果设置了反爬等措施,校验一下反爬(头 token)
        2)没有token,返回None,代表游客
        3)有token,进入校验
              -- 不通过:抛AuthenticationFailed异常,代表非法用户
              -- 通过:返回 (user, token),代表合法用户
        """
        pass

3、权限组件

#1、配置drf自带的权限类(有需求):
from rest_framework.permissions import IsAuthenticated, IsAdminUser, AllowAny, IsAuthenticatedOrReadOnly

#权限组件一般适用于局部所有在使用的时候,将需要设置权限的类中添加下面两种形式配置
    permission_classes = [IsAuthenticated]#==>允许登录用户
    permission_classes = [IsAdminUser] #==>只允许管理员用户
    AllowAny #==> 不限制
    IsAuthenticatedOrReadOnly#==>游客用户只读
    
#2、自定义权限组件:
from rest_framework.permissions import BasePermission

"""
自定义权限类
1) drf默认提供了一些权限类
    AllowAny:游客和登录用户有全权限
    IsAuthenticated:只有登录用户有全权限
    IsAdminUser:只有后台用户(admin用户)有全权限
    IsAuthenticatedOrReadOnly:游客有读权限,登录用户有全权限
2)如果有特殊需要,需要自定义权限类
    如:只有superuser有权限、只有vip用户有权限、只有某ip网段用户有权限、只有某个视图及其子类有权限
"""
class MyPermission(BasePermission):
    def has_permission(self, request, view):
        """
        1) 根据需求,request和view的辅助,制定权限规则判断条件
        2)如果条件通过,返回True
        3)如果条件不通过,返回False
        """
        print(request.user, request.auth)
        return False


# eg:VIP用户权限
class VIPUserPermission(BasePermission):
    def has_permission(self, request, view):
        for group in request.user.groups.all():
            if group.name.lower() == 'vip':
                return True
        return False
    
    
#eg:使用的时候在视图类中:
from rest_framework.viewsets import ViewSet
class UserViewSet(ViewSet):
    # 权限:只有VIP用户可以查看个人详细详细
    permission_classes = [permissions.VIPUserPermission]
    #单查方法
    def retrieve(self, request, *args, **kwargs):
        return APIResponse(results={
            #request.user通过点方法获取用户信息
            'username': request.user.username,
            'email': request.user.email,
            'mobile': request.user.mobile,
            'data_joined': request.user.date_joined,
        })

总结认证与权限组件绑定使用

? 1)每一个视图类都要进行认证校验,且认证规则一致,所以全局配置认证类即可
? 2)每一个视图类都要进行权限校验,默认配置的是不限制(AllowAny),但实际开发中,视图类的访问权限不尽相同,所以要在具体的视图类,配置具体的权限规则

4、频率组件

#1、配置drf自带的频率类(有需求)
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
#自带AnonRateThrottle不做频率限制,UserRateThrottle限制游客用户访问频率
throttle_classes = [UserRateThrottle]
# drf框架自定义配置
REST_FRAMEWORK = {
    # 频率组件:频率类一般做局部配置,但是频率调节在settings中配置
    'DEFAULT_THROTTLE_RATES': {
        'user': '5/min',
        'anon': '3/min',
        'mobile': '1/min'
    },
}
#2、配置自定义的频率类(需求大)建议将自定义频率单独放到一个throttles.py文件中在视图类中导入
from rest_framework.throttling import SimpleRateThrottle
"""
自定义频率类
1) drf默认提供了一些频率类 
    AnonRateThrottle:只对游客进行频率限制
    UserRateThrottle:对所有用户进行频率限制
2)如果有特殊需要,需要自定义频率类
    如:对ip进行限次、对电话进行限制、对视图某些信息进行限次
"""
class MobileRateThrottle(SimpleRateThrottle):
    """
    1)设置scope字符串类属性,同时在settings中进行drf配置DEFAULT_THROTTLE_RATES
        eg: DEFAULT_THROTTLE_RATES = {'mobile': '1/min'}
    2)重写get_catch_key方法:
        返回与限制条件有关的字符串,表示限制
        返回None,表示不限制
    """
    scope = 'mobile'
    def get_cache_key(self, request, view):
        if not request.user.is_authenticated or not request.user.mobile:
            return None  # 匿名用户 或 没有电话号的用户 都不限制

        # 只要有电话号的用户踩进行限制
        return self.cache_format % {
            'scope': self.scope,
            'ident': request.user.mobile
        }
#在视图类中配置
throttle_classes = [throttles.MobileRateThrottle]

5、多方式登录

多方式登录分析

'''
自定义签发token - 多方式登录
1)将请求数据交给序列化类,执行序列化校验
2)在序列化全局校验钩子中,完成user的认证与token的签发,保存在序列化对象的content中
3)在视图类中从序列化对象的content中拿user与token相关信息返回
注:多方式登录体现在 请求的账号类型可能是用户名、邮箱或手机等,采用不同字段校验数据库即可
'''

视图中

# 多方式登录
from rest_framework.views import APIView
class LoginAPIView(APIView):
    """ 重点
    1)token只能由 登录接口 签发
    2)登录接口也是APIView的子类,使用一定会进行 认证、权限 组件的校验
    结论:不管系统默认、或是全局settings配置的是何认证与权限组件,登录接口不用参与任何认证与权限的校验
    所以,登录接口一定要进行 认证与权限 的局部禁用
    """
    authentication_classes = [] #设置认证为空,局部禁用
    pagination_class = [] #设置权限为空,局部禁用

    def post(self, request, *args, **kwargs):
        serializer = serializers.LoginModelSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)  # 内部在全局钩子中完成token的签发
        return APIResponse(results={
            'username': serializer.content.get('user').username,
            'token': serializer.content.get('token')
        })

序列化中

from rest_framework import serializers
from . import models
from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
import re
class LoginModelSerializer(serializers.ModelSerializer):
    # post请求,序列化默认当做create动作进行校验,需要校验数据库,create动作username会抛用户已存在异常
    # 抛用户已存在异常是多余的,所以自定义系统校验规则即可
    username = serializers.CharField(min_length=3, max_length=16)
    password = serializers.CharField(min_length=3, max_length=16)
    class Meta:
        model = models.User
        fields = ('username', 'password')

    # 用全局钩子,完成token的签发
    def validate(self, attrs):
        # 1)通过 username 和 password 完成多方式登录校验,得到user对象
        user = self._validate_user(attrs)
        # 2)user对象包装payload载荷
        payload = jwt_payload_handler(user)
        # 3)payload载荷签发token
        token = jwt_encode_handler(payload)
        # 4)将user与token存储到serializer对象中,方便在视图类中使用
        self.content = {
            'user': user,
            'token': token
        }
        return attrs

    def _validate_user(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')

        if re.match(r'.*@.*', username):  # 邮箱
            user = models.User.objects.filter(email=username).first()  # type: models.User
        elif re.match(r'^1[3-9][0-9]{9}$', username):  # 电话
            user = models.User.objects.filter(mobile=username).first()
        else:  # 用户名
            user = models.User.objects.filter(username=username).first()

        if not user or not user.check_password(password):
            raise serializers.ValidationError({'message': '用户信息异常'})

        return user

以上是关于三大认证的主要内容,如果未能解决你的问题,请参考以下文章

79- drf三大认证的配置及使用方法

drf三大认证:认证组件-权限组件-权限六表-自定义认证组件的使用

三大认证

三大认证组件

三大认证

DRF三大认证