drf三大认证

认证组件authentication

一般使用全局配置

settings中配置
REST_FRAMEWORK = {
    # 认证组件
    'DEFAULT_AUTHENTICATION_CLASSES': [
        #系统自带两个认证类
        # 'rest_framework.authentication.SessionAuthentication',
        # 'rest_framework.authentication.BasicAuthentication'
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication'
    ],
}
自定义权限类
  1. 如果使用session认证,drf提供了SessionAuthentication类认证
  2. 如果使用drf-jwt认证框架,drf-jwt提供了JSONWebTokenAuthentication类认证
  3. 如果自定义签发与校验token,需要将校验token的算法封装到自定义的认证类中.
    1. 从请求头中获取前台提交的token(一般从HTTP_AUTHORIZATION中拿,也可以与前台交流好),这是为了设置反爬措施,校验反爬.
    2. 没有token,返回None,代表游客.
    3. 由token,进入校验.
      1. 不通过,抛出AuthenticationFailed异常,代表非法用户
      2. 通过,返回(user,token)二元组,代表合法用户
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        pass

总结:

不带或者认证格式错误,相当于游客访问,

带了正确的请求格式,但是token信息错误,为非法用户,并抛出AuthenticationFailed异常

权限组件permission

一般使用局部配置,导入模块,在视图函数中配置组件

permission_classes = [IsAuthenticated]

系统自带权限类

AllowAny:游客和登录用户有全权限

IsAuthenticated:只有登录用户有全权限

IsAdminUser:只有后台用户(admin用户)有全权限

IsAuthenticatedOrReadOnly:游客有读权限,登录用户有全权限

也可以全局配置
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
'DEFAULT_PERMISSION_CLASSES': [
    'rest_framework.permissions.AllowAny',
],
自定义权限类

如有特殊需求,比如:只有superuser有权限、只有vip用户有权限、只有某ip网段用户有权限、只有某个视图及其子类有权限.

has_permission方法的返回值为bool型,True为拥有权限,反之False无权限.

class MyPermission(BasePermission):
    def has_permission(self, request, view):
        """
        1) 根据需求,request和view的辅助,制定权限规则判断条件
        2)如果条件通过,返回True
        3)如果条件不通过,返回False
        """
        print(request.user, request.auth)
        return True

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 #无权限

频率组件throttle

settings中配置,

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

不配置默认无频率认证

drf默认提供了一些频率类

AnonRateThrottle:只对游客进行频率限制

UserRateThrottle:对所有用户进行频率限制

自定义配置

如果有特殊需求,需要自定义频率类

如:对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
        }

多方式登录

  1. token只能由 登录接口 签发
  2. 登录接口也是APIView的子类,使用一定会进行 认证,权限 组件的校验

结论:不管系统默认,或是全局settings配置的何种认证与权限组件,登录接口不用参与任何认证与权限的校验

所以,登录接口一定要进行 认证与权限的局部禁用

方法

登录接口中设置局部禁用

class LoginAPIView(APIView):
    #认证与权限接口的局部禁用
    authentication_classes = []
    permission_classes = []

    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')
        })

多方式登录的验证规则刚在serializers中,通过全局钩子进行校验

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
posted @ 2020-01-02 21:38  Agsol  阅读(157)  评论(0编辑  收藏  举报