1. 程式人生 > >Django-Rest frameworw認證和許可權

Django-Rest frameworw認證和許可權

一、認證已封裝好的類

	from rest_framework.authentication import BaseAuthentication
	class BaseAuthentication(object):
		def authenticate(self, request):
			#三種返回結果
			1、 return (user,auth) #當前認證處理後,認證環節結束,不在執行後面的認證了
			2、 return None  #不處理,讓後面認證處理
			3、 raise  raise #exceptions.AuthenticationFailed("使用者認證失敗")


		def authenticate_header(self, request):
			# 驗證失敗時,返回的響應頭WWW-Authenticate對應的值
			pass

	class BasicAuthentication(BaseAuthentication):
		'請求頭認證'
		pass

	class SessionAuthentication(BaseAuthentication):
		'session認證'
		pass
	class TokenAuthentication(BaseAuthentication):
		'token認證,' 
		pass

二、許可權已封裝好的類

from rest_framework.permissions import BasePermission
class BasePermission(object):
	

	message = "許可權驗證失敗" #定製驗證的錯誤資訊

	def has_permission(self, request, view):
		'判斷是否有許可權訪問當前請求'
		return True #/ False

	# GenericAPIView中get_object時呼叫
	def has_object_permission(self, request, view, obj):
		'檢視繼承GenericAPIView,並在其中使用get_object時獲取物件時,觸發單獨物件許可權驗證'
		return True # / False

class AllowAny(BasePermission):
	'任何人都能訪問,和沒設定一樣'
	def has_permission(self, request, view):
	return True

class IsAuthenticated(BasePermission):
	'登入後,才能訪問'
	def has_permission(self, request, view):
    return request.user and request.user.is_authenticated

class IsAdminUser(BasePermission):
	'只允許,admin使用者訪問'

class IsAuthenticatedOrReadOnly(BasePermission):
	'登入後,請求方式允許(get , put) 才能訪問 '

class DjangoModelPermissions(BasePermission):
	'不清楚'

1、def authenticate_header(self, request): #作用


生成這樣的登入介面(瀏覽器自帶的登入介面)


三、認證示例展示

============*****============

        1、使用者url傳入的token認證     #區域性 或 全域性類使用

        2、請求頭認證

        3. 多個認證規則

        4.認證和許可權

============*****============

   1、使用者url傳入的token認證

in url.py
	from django.conf.urls import url, include
	from web.viewsimport TestView

	urlpatterns = [
		url(r'^test/', TestView.as_view()),
	]


in view.py
	from rest_framework.views import APIView
	from rest_framework.response import Response
	from rest_framework.authentication import BaseAuthentication
	from rest_framework.request import Request
	from rest_framework import exceptions

	token_list = [
	    'sfsfss123kuf3j123',
	    'asijnfowerkkf9812',
	]


	class TestAuthentication(BaseAuthentication):
	    def authenticate(self, request):
	        """
	        使用者認證,如果驗證成功後返回元組: (使用者,使用者Token)
	        :param request: 
	        :return: 
	            None,表示跳過該驗證;
	                如果跳過了所有認證,預設使用者和Token和使用配置檔案進行設定
	                self._authenticator = None
	                if api_settings.UNAUTHENTICATED_USER:
	                    self.user = api_settings.UNAUTHENTICATED_USER()
	                else:
	                    self.user = None
	        
	                if api_settings.UNAUTHENTICATED_TOKEN:
	                    self.auth = api_settings.UNAUTHENTICATED_TOKEN()
	                else:
	                    self.auth = None
	            (user,token)表示驗證通過並設定使用者名稱和Token;
	            AuthenticationFailed異常
	        """
	        val = request.query_params.get('token')
	        if val not in token_list:
	            raise exceptions.AuthenticationFailed("使用者認證失敗")

	        return ('登入使用者', '使用者token')

	    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.
	        """
	        # 驗證失敗時,返回的響應頭WWW-Authenticate對應的值
	        pass

	方式一:定義區域性類(認證、許可權等)
		class TestView(APIView):
		    authentication_classes = [TestAuthentication, ]
		    permission_classes = []

		    def get(self, request, *args, **kwargs):
		        print(request.user)
		        print(request.auth)
		        return Response('GET請求,響應內容')

		    def post(self, request, *args, **kwargs):
		        return Response('POST請求,響應內容')

		    def put(self, request, *args, **kwargs):
		        return Response('PUT請求,響應內容')


	方式二:(推薦)在使用區域性類 ,或者TestView不想使用全域性的類(認證、許可權等)

		class MyTokenAuthentication(object):
			authentication_classes = [TestAuthentication, ] 
			permission_classes = []

		class TestView(MyTokenAuthentication,APIView): #MyTokenAuthentication 要放在前面,
						#否則authentication_classes 就從全域性(settings)裡找

		    def get(self, request, *args, **kwargs):
		        print(request.user)
		        print(request.auth)
		        return Response('GET請求,響應內容')

		    def post(self, request, *args, **kwargs):
		        return Response('POST請求,響應內容')

		    def put(self, request, *args, **kwargs):
		        return Response('PUT請求,響應內容')
    2、請求頭認證
in url.py
	from django.conf.urls import url, include
	from web.viewsimport TestView

	urlpatterns = [
		url(r'^test/', TestView.as_view()),
	]

in view.py
	#!/usr/bin/env python
	# -*- coding:utf-8 -*-
	from rest_framework.views import APIView
	from rest_framework.response import Response
	from rest_framework.authentication import BaseAuthentication
	from rest_framework.request import Request
	from rest_framework import exceptions

	token_list = [
	    'sfsfss123kuf3j123',
	    'asijnfowerkkf9812',
	]


	class TestAuthentication(BaseAuthentication):
	    def authenticate(self, request):
	        """
	        使用者認證,如果驗證成功後返回元組: (使用者,使用者Token)
	        :param request: 
	        :return: 
	            None,表示跳過該驗證;
	                如果跳過了所有認證,預設使用者和Token和使用配置檔案進行設定
	                self._authenticator = None
	                if api_settings.UNAUTHENTICATED_USER:
	                    self.user = api_settings.UNAUTHENTICATED_USER()
	                else:
	                    self.user = None
	        
	                if api_settings.UNAUTHENTICATED_TOKEN:
	                    self.auth = api_settings.UNAUTHENTICATED_TOKEN()
	                else:
	                    self.auth = None
	            (user,token)表示驗證通過並設定使用者名稱和Token;
	            AuthenticationFailed異常
	        """
	        import base64
	        auth = request.META.get('HTTP_AUTHORIZATION', b'')
	        if auth:
	            auth = auth.encode('utf-8')
	        auth = auth.split()
	        if not auth or auth[0].lower() != b'basic':
	            raise exceptions.AuthenticationFailed('驗證失敗')
	        if len(auth) != 2:
	            raise exceptions.AuthenticationFailed('驗證失敗')
	        username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':') # partition 切割和split類似,
	        if username == 'alex' and password == '123':                      # 但 'xxx:yyy'.partition(":") = ['xxx',':','yyy']
	            return ('登入使用者', '使用者token')
	        else:
	            raise exceptions.AuthenticationFailed('使用者名稱或密碼錯誤')

	    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.
	        """
	        return 'Basic realm=api'


	class TestView(APIView): # 關注  1、使用者url傳入的token認證 的TestView使用
	    authentication_classes = [TestAuthentication, ] 
	    permission_classes = []

	    def get(self, request, *args, **kwargs):
	        print(request.user)
	        print(request.auth)
	        return Response('GET請求,響應內容')

	    def post(self, request, *args, **kwargs):
	        return Response('POST請求,響應內容')

	    def put(self, request, *args, **kwargs):
	        return Response('PUT請求,響應內容')
3. 多個認證規則
in url.py
	from django.conf.urls import url, include
	from web.views.s2_auth import TestView

	urlpatterns = [
	    url(r'^test/', TestView.as_view()),
	]

in view.py
	#!/usr/bin/env python
	# -*- coding:utf-8 -*-
	from rest_framework.views import APIView
	from rest_framework.response import Response
	from rest_framework.authentication import BaseAuthentication
	from rest_framework.request import Request
	from rest_framework import exceptions

	token_list = [
	    'sfsfss123kuf3j123',
	    'asijnfowerkkf9812',
	]


	class Test1Authentication(BaseAuthentication):
	    def authenticate(self, request):
	        """
	        使用者認證,如果驗證成功後返回元組: (使用者,使用者Token)
	        :param request: 
	        :return: 
	            None,表示跳過該驗證;
	                如果跳過了所有認證,預設使用者和Token和使用配置檔案進行設定
	                self._authenticator = None
	                if api_settings.UNAUTHENTICATED_USER:
	                    self.user = api_settings.UNAUTHENTICATED_USER() # 預設值為:匿名使用者
	                else:
	                    self.user = None

	                if api_settings.UNAUTHENTICATED_TOKEN:
	                    self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 預設值為:None
	                else:
	                    self.auth = None
	            (user,token)表示驗證通過並設定使用者名稱和Token;
	            AuthenticationFailed異常
	        """
	        import base64
	        auth = request.META.get('HTTP_AUTHORIZATION', b'')
	        if auth:
	            auth = auth.encode('utf-8')
	        else:
	            return None
	        print(auth,'xxxx')
	        auth = auth.split()
	        if not auth or auth[0].lower() != b'basic':
	            raise exceptions.AuthenticationFailed('驗證失敗')
	        if len(auth) != 2:
	            raise exceptions.AuthenticationFailed('驗證失敗')
	        username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':')
	        if username == 'alex' and password == '123':
	            return ('登入使用者', '使用者token')
	        else:
	            raise exceptions.AuthenticationFailed('使用者名稱或密碼錯誤')

	    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.
	        """
	        # return 'Basic realm=api'
	        pass

	class Test2Authentication(BaseAuthentication):
	    def authenticate(self, request):
	        """
	        使用者認證,如果驗證成功後返回元組: (使用者,使用者Token)
	        :param request: 
	        :return: 
	            None,表示跳過該驗證;
	                如果跳過了所有認證,預設使用者和Token和使用配置檔案進行設定
	                self._authenticator = None
	                if api_settings.UNAUTHENTICATED_USER:
	                    self.user = api_settings.UNAUTHENTICATED_USER() # 預設值為:匿名使用者
	                else:
	                    self.user = None
	        
	                if api_settings.UNAUTHENTICATED_TOKEN:
	                    self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 預設值為:None
	                else:
	                    self.auth = None
	            (user,token)表示驗證通過並設定使用者名稱和Token;
	            AuthenticationFailed異常
	        """
	        val = request.query_params.get('token')
	        if val not in token_list:
	            raise exceptions.AuthenticationFailed("使用者認證失敗")

	        return ('登入使用者', '使用者token')

	    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.
	        """
	        pass


	class TestView(APIView):
	    authentication_classes = [Test1Authentication, Test2Authentication]  # 某個認證處理完就結束了,之後的認證失效
	    permission_classes = [] # 許可權是每個類都要經過




	    def get(self, request, *args, **kwargs):
	        print(request.user)
	        print(request.auth)
	        return Response('GET請求,響應內容')

	    def post(self, request, *args, **kwargs):
	        return Response('POST請求,響應內容')

	    def put(self, request, *args, **kwargs):
	        return Response('PUT請求,響應內容')

4.認證和許可權

in url.py
	from django.conf.urls import url, include
	from web.views import TestView

	urlpatterns = [
	    url(r'^test/', TestView.as_view()),
	]

in view.py
	#!/usr/bin/env python
	# -*- coding:utf-8 -*-
	from rest_framework.views import APIView
	from rest_framework.response import Response
	from rest_framework.authentication import BaseAuthentication
	from rest_framework.permissions import BasePermission

	from rest_framework.request import Request
	from rest_framework import exceptions

	token_list = [
	    'sfsfss123kuf3j123',
	    'asijnfowerkkf9812',
	]


	class TestAuthentication(BaseAuthentication):
	    def authenticate(self, request):
	        """
	        使用者認證,如果驗證成功後返回元組: (使用者,使用者Token)
	        :param request: 
	        :return: 
	            None,表示跳過該驗證;
	                如果跳過了所有認證,預設使用者和Token和使用配置檔案進行設定
	                self._authenticator = None
	                if api_settings.UNAUTHENTICATED_USER:
	                    self.user = api_settings.UNAUTHENTICATED_USER() # 預設值為:匿名使用者
	                else:
	                    self.user = None
	        
	                if api_settings.UNAUTHENTICATED_TOKEN:
	                    self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 預設值為:None
	                else:
	                    self.auth = None
	            (user,token)表示驗證通過並設定使用者名稱和Token;
	            AuthenticationFailed異常
	        """
	        val = request.query_params.get('token')
	        if val not in token_list:
	            raise exceptions.AuthenticationFailed("使用者認證失敗")

	        return ('登入使用者', '使用者token')

	    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.
	        """
	        pass


	class TestPermission(BasePermission):
	    message = "許可權驗證失敗" # 錯誤資訊

	    def has_permission(self, request, view):
	        """
	        判斷是否有許可權訪問當前請求
	        兩種返回結果
		        return True  # 許可權驗證通過,執行下一個許可權類
		        return False # 檢測為False  然後就raise 報錯  
	        """
	        if request.user == "管理員":
	            return True

	    # GenericAPIView中get_object時呼叫
	    def has_object_permission(self, request, view, obj):
	        """
	        檢視繼承GenericAPIView,並在其中使用get_object時獲取物件時,觸發單獨物件許可權驗證
	        Return `True` if permission is granted, `False` otherwise.
	        :param request: 
	        :param view: 
	        :param obj: 
	        :return: True有許可權;False無許可權
	        """
	        if request.user == "管理員":
	            return True


	class TestView(APIView):
	    # 認證的動作是由request.user觸發
	    authentication_classes = [TestAuthentication, ]

	    # 許可權
	    # 迴圈執行所有的許可權
	    permission_classes = [TestPermission, ]

	    def get(self, request, *args, **kwargs):
	        # self.dispatch
	        print(request.user)
	        print(request.auth)
	        return Response('GET請求,響應內容')

	    def post(self, request, *args, **kwargs):
	        return Response('POST請求,響應內容')

	    def put(self, request, *args, **kwargs):
	        return Response('PUT請求,響應內容')