欢迎来到Louis的博客

人生三从境界:昨夜西风凋碧树,独上高楼,望尽天涯路。 衣带渐宽终不悔,为伊消得人憔悴。 众里寻他千百度,蓦然回首,那人却在灯火阑珊处。
扩大
缩小

03-Drf认证

 

使用token对用户的访问进行认证,认证不通过的用户返回非法提示

编写登录视图

drf_auth.viewss.py

class Login(APIView):
    def post(self, request):
        # 响应的字典
        response = dict()
        fields = {'username', 'password'}
        user_info = dict()
        if fields.issubset(set(request.data)):
            for key in fields:
                user_info[key] = request.data[key]
        
        # 使用Django认证组件进行校验
        user_instance = authenticate(**user_info)
        
        # 校验成功
        if user_instance is not None:
            # 生成token
            access_token = generate_token()
            # 更新或创建Token
            UserToken.objects.update_or_create(user=user_instance, defaults={'token': access_token})
            response['status_code'] = 200
            response['status_message'] = '登录成功'
            response['access_token'] = access_token
            response['user_role'] = user_instance.get_user_level_display()
        else:
            # 校验失败
            response['status_code'] = 201
            response['status_message'] = '用户名或密码错误'

        return Response(response)

postman测试登录

根据规则,没有登录用户,无权限访问books路由

定义认证类

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import APIException
# 自定义认证类,需要重写authenticate方法,该方法里写认证逻辑代码,认证失败抛出APIException异常
class UserAuth(BaseAuthentication):
    def authenticate(self, request):
        user_token = request.query_params.get('token')
        try:
            token = UserToken.objects.get(token=user_token)
    #在rest framework内部会将这两个字段赋值给request,以供后续操作使用
     return token.user, token.token except Exception as e: raise APIException('非法访问用户')

使用认证类

全局配置

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ['utils.auth_component.UserAuth'],
}

登录和注册不需要认证,其他所有页面都需要登录后才能访问,我们用postman发送请求测试下

class Login(APIView):
    authentication_classes = []
    .....


class Reg(APIView):
    authentication_classes = []
    ....

登录无认证限制

其他路由,非认证用户限制访问

带token用户,正常访问。

 

局部配置

根据业务场景来看,部分路由只能登录用户访问,这时就不用配置全局,对单独视图类进行配置

from utils.auth_component import UserAuth


class BookView(ModelViewSet):
   # 认证 authentication_classes
= [UserAuth] queryset = Book.objects.all() serializer_class = BookSerialize

BaseAuthentication源码

class BaseAuthentication(object):
    """
    All authentication classes should extend BaseAuthentication.
    """

    def authenticate(self, request):
        """
        Authenticate the request and return a two-tuple of (user, token).
        """
        #内置的认证类,authenticate方法,如果不自己写,默认则抛出异常
        raise NotImplementedError(".authenticate() must be overridden.")

    def authenticate_header(self, request):
        """
        Return a string to be used as the value of the `WWW-Authenticate`
        header in a `401 Unauthenticated` response, or `None` if the
        authentication scheme should return `403 Permission Denied` responses.
        """
        #authenticate_header方法,作用是当认证失败的时候,返回的响应头
        pass

其它内置认证类

 rest_framework里面还内置了其它认证类,我们主要用到的就是BaseAuthentication,剩下的很少用到

总结

 自己写认证类方法梳理

 (1)创建认证类

  • 继承BaseAuthentication    --->>1.重写authenticate方法;2.authenticate_header方法直接写pass就可以(这个方法必须写)

(2)authenticate()返回值(三种)

  • None ----->>>当前认证不管,等下一个认证来执行
  • raise exceptions.AuthenticationFailed('用户认证失败')       # from rest_framework import exceptions
  •  有返回值元祖形式:(元素1,元素2)      #元素1复制给request.user;  元素2复制给request.auth

 (3)局部使用

  • authentication_classes = [BaseAuthentication,]

(4)全局使用

#设置全局认证
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ['utils.auth_component.UserAuth'],
}

 

源码流程

--->>dispatch

    --封装request

       ---获取定义的认证类(全局/局部),通过列表生成式创建对象 

     ---initial

       ----peform_authentication

         -----request.user   (每部循环创建的对象)

    

 

posted on 2018-12-10 10:52  Louiszj  阅读(182)  评论(0)    收藏  举报

导航