二、REST framework的三大组件之一:认证
前置条件:新建视图类;并配置路由
class LoginView(MyAPIView): def get(self, request, *args, **kwargs): return Response('GET') class UserView(MyAPIView): def get(self, request, *args, **kwargs): return Response('GET') class OrderView(MyAPIView): def get(self, request, *args, **kwargs): return Response('GET') url配置: path('api/<str:version>/LoginView/', views.LoginView.as_view()), path('api/<str:version>/UserView/', views.UserView.as_view()), path('api/<str:version>/OrderView/', views.OrderView.as_view()),
1、导入rest_framework的认证类,并导入认证失败时,需要触发的认证异常类
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed
2、认证类基本用法
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed # 新建认证类 class MyAuthentication(BaseAuthentication): def authenticate(self, request): # 获取请求中的token信息 token = request.query_params.get('token') if token: # 认证成功,以元组的形式返回认证信息 return "pass", token else: # 认证失败,返回认证失败信息 raise AuthenticationFailed({'code': 100001, 'msg': '认证失败'}) # 此方法可以认为注释方法,可有可无 def authenticate_header(self, request): return 'API' class LoginView(MyAPIView): # authentication_classes 为认证类的默认配置参数,必须怎么写,详细过程可以查看源码 # 当不使用认证类时,列表为空 authentication_classes = [] def get(self, request, *args, **kwargs): return Response('GET') class UserView(MyAPIView): # 使用认证类时,列表中,添加认证类 authentication_classes = [MyAuthentication, ] def get(self, request, *args, **kwargs): return Response('GET') class OrderView(MyAPIView): # 使用认证类时,列表中,添加认证类 authentication_classes = [MyAuthentication, ] def get(self, request, *args, **kwargs): return Response('GET') # 接口访问结果: # 1、LoginView正常返回 # 2、UserView不带token时,返回认证失败 # { # "code": "100001", # "msg": "认证失败" # } # 2.1 带token时,正常返回,OrderView同理
3、 全局配置
3.1、新建python文件夹和 myAuthentication.py文件,并把认证类迁移到myAuthentication中

3.2、通过源码可以知道,默认认证类调用的是APIView中的 DEFAULT_AUTHENTICATION_CLASSES 配置,所以settings添加全局配置
REST_FRAMEWORK = { "UNAUTHENTICATED_USER": None, # 用户配置 # 认证配置 "DEFAULT_AUTHENTICATION_CLASSES": ["auto_project.auth.myAuthentication.QueryParamsAuthentication",] }
3.3、修改视图类,并再次访问接口
class LoginView(MyAPIView): # authentication_classes 为认证类的默认配置参数,必须怎么写,详细过程可以查看源码 # 当不使用认证类时,列表为空 # 请注意,当类中使用authentication_classes=[认证类1, 认证类2, ...]时,认证默认使用就近原则,使用类中的authentication_classes authentication_classes = [] def get(self, request, *args, **kwargs): return Response('GET') class UserView(MyAPIView): def get(self, request, *args, **kwargs): return Response('GET') class OrderView(MyAPIView): def get(self, request, *args, **kwargs): return Response('GET') # 接口访问结果: # 1、LoginView正常返回 # 2、UserView不带token时,返回认证失败 # { # "code": "100001", # "msg": "认证失败" # } # 2.1 带token时,正常返回,OrderView同理
4、多个认证类应用
4,1、多个认证源码解析<只看运行过程,源码位于request中的initialize_request中<关注这个地方,学习权限时,源码位置有所不同>
def _authenticate(self): """ Attempt to authenticate the request using each authentication instance in turn. """ # 认证类源码 for authenticator in self.authenticators: try: # 循环认证类 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 return
4.2、通过源码知道当有多个认证类时,循环认证类,单个认证类返回为空时,再走下一个认证类,根据实际应用,认证条件可以放到请求体、头部或url中,基于此条件修改认证类
class QueryParamsAuthentication(BaseAuthentication): # 通过url获取token def authenticate(self, request): token = request.query_params.get('token') # 结合源码为空时,走下一个认证类 if not token: return # 当token不为空时,从数据库中获取token db_data = UserInfo.objects.filter(token=token).first() # 当token数据库中token不为空时,返回数据数据对象和token if db_data: return db_data, token # 数据库无token时,返回空 return def authenticate_header(self, request): return 'API' # 通过头部获取 class HeaderAuthentication(BaseAuthentication): def authenticate(self, request): token = request.META.get('HTTP_AUTHORIZATION') # postmen发送请求时, 使用AUTHORIZATION, HTTP_ 为django自己拼接 if not token: return db_data = UserInfo.objects.filter(token=token).first() if db_data: return db_data, token return def authenticate_header(self, request): return 'API' # 通过Body体获取token class BodyAuthentication(BaseAuthentication): def authenticate(self, request): token = request.data.get('token') if not token: return db_data = UserInfo.objects.filter(token=token).first() if db_data: return db_data, token return def authenticate_header(self, request): return 'API' # 当认证类循环完成后,没有找到token时,才触发认证失败 class NoAuthentication(BaseAuthentication): def authenticate(self, request): raise AuthenticationFailed({'code': 100001, 'msg': '认证失败'}) def authenticate_header(self, request): return 'API'
4.3、案例-用户登录和认证
1、models中添加表userInfo,并同步到数据库中
class UserInfo(models.Model): db_table = 'userinfo' username = models.CharField(verbose_name='用户名', max_length=32) password = models.CharField(verbose_name='密码', max_length=64) token = models.CharField(verbose_name='token', max_length=64) role = models.IntegerField(verbose_name='角色', choices=((1, '总监'), (2, '经理'), (3, '员工')), default=3)
2、数据库添加数据

3、添加视图类,并配置url
class LoginAPIView(MyAPIView): # 不使用认证类时,列表为空 authentication_classes = [] def get(self, request): username = request.query_params.get('username') password = request.query_params.get('password') # 查询是否有账号密码 db_userinfo = UserInfo.objects.filter(username=username, password=password).first() if not db_userinfo: return Response({'code': 100002, 'msg': '用户名密码错误'}) # 如果账号密码和token都存在,返回 elif db_userinfo and db_userinfo.token: return Response({'code': 200, 'token': db_userinfo.token, 'msg': 'suss'}) # 如果token不存在,生成uuid token = str(uuid.uuid4()) # 添加uuid到数据库中 db_userinfo.token = token db_userinfo.save() # 返回添加完成的token return Response({'code': 200, 'token': token, 'msg': 'suss'})
4、访问接口生成token

5、获取token信息后,再次访问之前的UserView接口,不加token时,因为有了全局认证配置,返回认证失败

6、在Params中加上token,再次访问,访问成功

7、把token放到头部信息中,再次访问,接口访问成功

8、body体中应用一致,不在演示, 关于认证返回的信息,在权限中可以用到,详细请学习权限模块功能点,连接:
https://i.cnblogs.com/posts/edit;postId=18632015

浙公网安备 33010602011771号