使用過API的同窗都知道,咱們不可能任意調用人家的API,由於經過API能夠獲取不少關鍵數據,並且這個API可能供多個部門或我的使用,因此必須是通過受權的用戶才能調用。python
API的使用過程通常是:數據庫
攜帶用戶名和密碼(或者是AK/SK)之類的信息進行登錄,得到一個受權的Token,後續經過此Token進行資源申請。流程圖以下:json
(A)用戶打開客戶端之後,客戶端要求用戶給予受權。 (B)用戶贊成給予客戶端受權,給用戶username和password。 (C)客戶端使用B中的信息得到的受權,向認證服務器申請令牌。 (D)認證服務器對客戶端進行認證之後,確認無誤,贊成發放令牌。 (E)客戶端使用令牌,向資源服務器申請獲取資源。 (F)資源服務器確認令牌無誤,贊成向客戶端開放資源。
urls文件api
url(r'^login/$', views.LoginView.as_view(),name="login"),
新增用戶表和token表服務器
class User(models.Model): name=models.CharField(max_length=32) pwd=models.CharField(max_length=32) class Token(models.Model): user=models.OneToOneField("User") token = models.CharField(max_length=128) def __str__(self): return self.token
用戶表api序列化app
class AuthorModelSerializers(serializers.ModelSerializer): class Meta: model = Author fields = "__all__"
一、實現user表APIdom
二、經過LoginView函數,實現用戶登錄,登錄成功後保存token到數據庫,並返回給用戶信息;登錄失敗則給用戶提示。函數
注意:post
用戶每次登錄時纔會進行認證,生成一次token,不須要每次調用api接口都生成新的token。測試
class AuthorModelView(viewsets.ModelViewSet): queryset = Author.objects.all() serializer_class = AuthorModelSerializers def get_random_str(user): import hashlib,time ctime=str(time.time()) md5=hashlib.md5(bytes(user,encoding="utf8")) md5.update(bytes(ctime,encoding="utf8")) return md5.hexdigest() from .models import User class LoginView(APIView): def post(self,request): name=request.data.get("name") pwd=request.data.get("pwd") user=User.objects.filter(name=name,pwd=pwd).first() res = {"state_code": 1000, "msg": None} if user: random_str=get_random_str(user.name) token=Token.objects.update_or_create(user=user,defaults={"token":random_str}) res["token"]=random_str else: res["state_code"]=1001 #錯誤狀態碼 res["msg"] = "用戶名或者密碼錯誤" import json return Response(json.dumps(res,ensure_ascii=False))
def get_random_str(user): import hashlib, time ctime = str(time.time()) md5 = hashlib.md5(str(user)) md5.update(ctime) return md5.hexdigest()
將TokenAuth功能模塊單獨放入utils文件,便於擴展。
注意:
若是不繼承BaseAuthentication,則須要咱們本身寫authenticate_header函數。
def authenticate_header(self, request): pass
繼承BASEAuthenticate後,則能夠省略,由於他自帶了。
from rest_framework import exceptions from rest_framework.authentication import BaseAuthentication from .models import * class TokenAuth(BaseAuthentication): def authenticate(self,request): token = request.GET.get("token") token_obj = Token.objects.filter(token=token).first() if not token_obj: raise exceptions.AuthenticationFailed("驗證失敗123!") else: return token_obj.user.name,token_obj.token
當咱們只須要對局部資源進行認證時,能夠單獨設定authentication_classes變量,指定token功能模塊便可。
class AuthorModelView(viewsets.ModelViewSet): authentication_classes = [TokenAuth,] queryset = Author.objects.all() serializer_class = AuthorModelSerializers
測試:
加上Token後:
咱們在setttings文件裏面指定REST_FRAMEWORK變量便可。
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.TokenAuth",] }
全局應用後,全部資源都須要攜帶token才能訪問,若是不但願通過認證的話,能夠以下設置:
在對應View函數裏面,設置變量authentication_classes爲空列表便可。
authentication_classes = []