使用过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 = []