zoukankan      html  css  js  c++  java
  • django, django_restful 关于Authentication的学习总结

    一、关于配置

    django: 配置为AUTHENTICATION_BACKENDS,setting.py不写的话,AUTHENTICATION_BACKENDS默认设置为(‘django.contrib.auth.backends.ModelBackend’,),

              这是检测Django用户数据库的基本认证方案。按照 AUTHENTICATION_BACKENDS 的排列顺序,如果同样的用户名和密码在第一次就匹配了,那么Django将停止处理后面的东西        

    restful:  配置为 DEFAULT_AUTHENTICATION_CLASSES

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework.authentication.BasicAuthentication',
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.TokenAuthentication',
            'rest_framework_simplejwt.authentication.JWTAuthentication',
    
        ],
        'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
        'PAGE_SIZE': 2
    
    }
    
    AUTHENTICATION_BACKENDS = (
        #new
        'rest_framework.authentication.TokenAuthentication',
        #default  ModelBackend
        'django.contrib.auth.backends.ModelBackend',
    )

    二、django什么时候调用authenticate?

    1.django, 在login view中,进行用户验证时, 调用 django.contrib.auth.authenticate.

    def login_custom(request):
    
        if request.method == 'POST':
    
            # create a form instance and populate it with data from the request:
            form = myAuthenticationForm(request.POST)
            # check whether it's valid:
            if form.is_valid():
    
                username = form.cleaned_data['username']
                password = form.cleaned_data['password']
                user = authenticate(request, username=username, password=password)
                if user is not None:
    
                    login(request, user)
                    return redirect('login:home')
                else:
                    return render(request, 'registration_my/login_custom.html', {'form': form})

    验证的参数: 可以是username+password, 也可以是token, 

    返回:none 或  setting. AUTH_USER_MODEL (如果不custom,则是auth.user)

    注意,如果不调用 django.contrib.auth.authenticate. 那么setting. AUTHENTICATION_BACKENDS根本用不上,就不会被调用。

    三. restful 什么时候调用DEFAULT_AUTHENTICATION_CLASSES 中的定义类?

    参考:https://www.cnblogs.com/eric_yi/p/8422373.html

    在setting.py中,配置参数,token认证需要和权限认证配合使用

    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': (
    
            'rest_framework.permissions.IsAuthenticated',
    
        ),
    
        'DEFAULT_AUTHENTICATION_CLASSES': (
    
            'rest_framework.authentication.TokenAuthentication',
    
        ),
    }

     如下,所有继承 rest framework的APIView的类,都会走token认证,而有的view我们不需要认证,则在view中,指定permission_classes 和 authentication_classes为空,

    如下:则是不走token认证。

    class LoginView(APIView):
    authentication_classes = ()
    permission_classes = ()
    
    def post(self, request):
    username = request.data.get('username')
    password = request.data.get('password')

    (1) APIView中,不指定permission_classes = (xxx) 和 authentication_classes = (xxx),默认会进行setting.py中的 token认证。,发起请求时候,需要在请求头中添加 Authorization=Token 7d7770cb909ceead7d33ea7bafe7e6034ee012fc 

    (2)为需要的view指定permission_classes 和 authentication_classes, 则该view 不使用settings中添加REST_FRAMEWORK

    permission_classes = (permissions.AllowAny,) # 所有用户
    permission_classes = (permissions.IsAuthenticated,) # 登陆成功的token
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,) # 登陆成功的token,只能读操作
    permission_classes = (permissions.IsAdminUser,) # 登陆成功的管理员token

    注意,APIView中,调用 django.contrib.auth.authenticate时候,同样与普通django一样,调用的是配置参数AUTHENTICATION_BACKENDS中的内容

    四. restful 认证详解

    DEFAULT_AUTHENTICATION_CLASSES、AUTHENTICATION_BACKENDS 可以定制多个类, 有框架默认,还可以自己定制。
    1. 认证成功后的返回参数
    (1). 返回参数:restful authenticate 返回元组(return (toke_obj.user, toke_obj)) ,分别是user model 和 userToken model 的instanse
    (2). django 的authentivate返回user model instanse
    2. 配置多个authenticate时候循环调用机制
    如下,是restful的 APIView在进行request请求时候,层层跟踪,会执行如下语句,就是循环找认证函数的逻辑

    class APIView(View):
    as_view():dispatch():initialize_request():get_authenticators():
    self.authentication_classes
    self.perform_authentication 实现认证。 (认证就是取得user和token信息,至于是否拒绝访问,主要看permission。
    
    
       def _authenticate(self):
            """
            Attempt to authenticate the request using each authentication instance
            in turn.
            """
            for authenticator in self.authenticators:
                try:
         #执行认证类的authenticate方法
                    #这里分三种情况
                    #1.如果authenticate方法抛出异常,self._not_authenticated()执行
                    #2.有返回值,必须是元组:(request.user,request.auth)
                    #3.返回None,表示当前认证不处理,等下一个认证来处理
                    user_auth_tuple = authenticator.authenticate(self)
                except exceptions.APIException:
                    self._not_authenticated()
                    raise
    
                if user_auth_tuple is not None:
                    self._authenticator = authenticator
                    self.user, self.auth = user_auth_tuple  #返回值对应示例中的token_obj.user和token_obj
                    return

     配置了多个authenticate, 则循环调用,遇到异常停止,返回none,说明不使用本认证,会依次调用下一个。

    最后若都没有返回值,就执行self._not_authenticated(),相当于匿名用户,没有通过认证,并且此时django会返回默认的匿名用户设置AnonymousUser

    注意,每一个APIView都需要认证,认证分全局和局部。
    全局:所有的未局部定义的APIView都有效
    #全局认证配置
    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES":['API.utils.auth.Authentication',]   #其中写认证的类的路径,不要在views中,这里我放在了utils目录下auth.py中
    }

    局部:在APIView中单独定义

    authentication_classes = []    #authentication_classes为空,代表不需要认证

     匿名:

    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES":['API.utils.auth.Authentication',],  #其中写认证的类的路径,不要在views中,这里我放在了utils目录下auth.py中
        "UNAUTHENTICATED_USER": lambda:"匿名"#匿名用户配置,只需要函数或类的对应的返回值,对应request.user="匿名"
    "UNAUTHENTICATED_token": None,#匿名token,只需要函数或类的对应的返回值,对应request.auth=None
    ##路径:rest_framework.authentication
    BaseAuthentication是django rest framework为我们提供了最基本的认证类
    BasicAuthentication  #基于浏览器进行认证
    SessionAuthentication #基于django的session进行认证
    RemoteUserAuthentication #基于django admin中的用户进行认证,这也是官网的示例
    TokenAuthentication #基于drf内部的token认证
    如何进行定制?
    (1)继承BaseAuthentication,重写authenticate方法和authenticate_header(pass就可以),authenticate()
    方法需要有三种情况(返回元祖、出现异常、返回none)。
    (2)定制完后,进行注册(配置)

    #全局认证
    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES":['API.utils.auth.Authentication',]
    }
    
    #局部认证
    authentication_classes = [BaseAuthentication,]
    
    #是某个视图不进行认证
    authentication_classes =[]

    restful的例子


    from rest_framework.views import APIView
    from rest_framework.response import Response
    class HelloView(APIView):
        def get(self, request):
            content = {'message': 'Hello, World!'}
            return Response(content)
    

      如上代码,不会走认证,被调用时候,会返回  200 {'message': 'Hello, World!'}

    class HelloView(APIView):
        permission_classes = (IsAuthenticated,)             # <-- And here
        def get(self, request):
            content = {'message': 'Hello, World!'}
            return Response(content)

    增加一行 permission_classes = (IsAuthenticated,)则只有认证过的用户才可以访问。

    直接被调动时候,报错,HTTP 403 Forbidden error.

    INSTALLED_APPS = [
        # Django Apps
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        # Third-Party Apps
        'rest_framework',
        'rest_framework.authtoken',  # <-- Here
        # Local Apps (Your project's apps)
        'myapi.core',
    ]
    
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework.authentication.TokenAuthentication',  # <-- And here
        ],
    }
    class HelloView(APIView): 
    在APIView
    中,不指定authentication_classes, 则默认都会用全局设定setting.DEFAULT_AUTHENTICATION_CLASSES,
    想单独去掉认证,则设定authentication_classes=[] ,想定制独特的认证,可以在APIView中设置。

    必须和permission_classes 结合在一起使用,才能限制API的访问。 认证过程,仅仅是取得request.user 和request.auth , 而permission才是去检查user和auth,去限制访问。

    五. django 认证详解

    1. AUTHENTICATION_BACKENDS 默认为'django.contrib.auth.backends.ModelBackend',
    认证成功,返回user model 否则 none

    2. contrib.auth.authenticate的代码, 它调用的
    AUTHENTICATION_BACKENDS
    def authenticate(request=None, **credentials):
        """
        If the given credentials are valid, return a User object.
        """
        for backend, backend_path in _get_backends(return_tuples=True):
            try:
                inspect.getcallargs(backend.authenticate, request, **credentials)
            except TypeError:
                # This backend doesn't accept these credentials as arguments. Try the next one.
                continue
            try:
                user = backend.authenticate(request, **credentials)
            except PermissionDenied:
                # This backend says to stop in our tracks - this user should not be allowed in at all.
                break
            if user is None:
                continue
            # Annotate the user object with the path of the backend.
            user.backend = backend_path
            return user
    
        # The credentials supplied are invalid to all backends, fire signal
        user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials), request=request)
    3. 我们(程序员)调用contrib.auth.auth.authenticate 时候,传入参数可以是
    username+userpassword 或者是Token , 因为
    **credentials接收的是{}字典
    def signup(request):
        if request.method == 'POST':
            form = UserCreationForm_simple(request.POST)
            if form.is_valid():
                form.save()
    
                username = form.cleaned_data.get('username')
                raw_password = form.cleaned_data.get('password1')
                user = authenticate(username=username, password=raw_password)
                login(request, user)
                return redirect('login:home')

    4. 如何定制 backends authentication

    参考 https://docs.djangoproject.com/en/3.0/topics/auth/customizing/

    An authentication backend is a class that implements two required methods:
     get_user(user_id) and authenticate(request, **credentials),其中,
    authenticate ()

    方法要返回user. 看起来这样:

    from django.contrib.auth.backends import BaseBackend
    
    class MyBackend(BaseBackend):
        def authenticate(self, request, username=None, password=None):
            # Check the username/password and return a user.

    或者

    from django.contrib.auth.backends import BaseBackend
    
    class MyBackend(BaseBackend):
        def authenticate(self, request, token=None):
            # Check the token and return a user.

    总结: authentication()就是检查用户的凭证(userame+password, 或者 token 或者其他,)成功则返回user,否则返回None

    注意,凭证不限于db, 也可以是文件,任意逻辑都可以,返回user则OK,官网实例是通过文件。

    5.定制完 class 后,要在setting 的 AUTHENTICATION_BACKENDS中,增加设置该class为候选。

    但这并不代表,服务启动了,它就被自动调用了。只有在需要登录的时候调用 contrib.auth.authenticate , contrib.auth.authenticate循环调用AUTHENTICATION_BACKENDS 的定义。

    按倒序,由里往外总结

    (1)定制 BACKEND authenticate, 加入到 setting.AUTHENTICATION_BACKENDS 列表中

    (2)contrib.auth.authenticate 循环调用 backend authenticate ,返回user 或 none 或抛出异常

    (3)在我们程序员自己的view中,如 loginView,  调用contrib.auth.authenticate,进行认证。

    def signup(request):
        if request.method == 'POST':
            form = UserCreationForm_simple(request.POST)
            if form.is_valid():
                form.save()
    
                username = form.cleaned_data.get('username')
                raw_password = form.cleaned_data.get('password1')
                user = authenticate(username=username, password=raw_password)
    
    
  • 相关阅读:
    Android Media Playback 中的MediaPlayer的用法及注意事项(二)
    Android Media Playback 中的MediaPlayer的用法及注意事项(一)
    34. Search for a Range
    33. Search in Rotated Sorted Array
    32. Longest Valid Parentheses
    31. Next Permutation下一个排列
    30. Substring with Concatenation of All Words找出串联所有词的子串
    29. Divide Two Integers
    28. Implement strStr()子串匹配
    27. Remove Element
  • 原文地址:https://www.cnblogs.com/lxgbky/p/12132117.html
Copyright © 2011-2022 走看看