前后端分离djangorestframework——认证组件
情况是这样的,项目用的restful规范,后端用的django+djangorestframework,前端用的vue-cli框架+webpack,前端与后端交互用的axios,然后再用户登录之后,axios添加token作为axios的header并请求后端,后端部分用的djangorestframework的认证组件。
以上的相关知识,不是本篇文章的重点,请移步:
前后端分离djangorestframework——认证组件
postman测试
在最开始写好后端
认证组件:
视图部分装饰认证组件:
vue部分,做了个判断,如果用户是登录状态,自动设置默认的headers:
添加了请求拦截器之后,前端会自动对每个请求之前请求一次,请求方式为options,之后再发出真实的请求
关于这个为什么会做两次请求是因为:
浏览器会对复杂请求进行处理,在发送真正的请求前, 会先发送一个方法为options的预请求(preflight request), 用于试探服务端是否能接受真正的请求,如果options获得的回应是拒绝性质的,比如404\403\500等http状态,就会停止post、put等请求的发出
有三种方式会导致这种现象:
- 请求方法不是get/head/post。即复杂请求
- post请求的content-type并非application/x-www-form-urlencoded, multipart/form-data, 或text/plain。最常见的json就不是
- 请求设置了自定义的header字段。我这里就设置了token作为自定义的headers
用的postman做的测试:
返回结果:
项目真实测试
然后在项目真实测试的时候:
前端用的vue-cli +webpack,启动项目,并抓包查看时,请求状态500
并且请求的参数并没有给上header
后端就是报错:
就是这个:
typeerror: cannot unpack non-iterable authenticationfailed object
并且前端的console部分还报同源策略的错:
我跟你说,你要是跑去后端设置中间件的response的话,你就距离正确答案越来越远了,我的中间件部分是这样的:
然后根据前面用postman测试都没问题,所以我判定,一定不是中间件的问题
思来想去,根本的原因就是拿不到token,所以我开始在这方面思考,然后我注释了那段是否带有token的判断,再测试:
打印request.meta
注释掉验证部分,只是打印看看request.meta里的数据
前端再次请求:
options请求方式因为已经取消了验证所以不报错了:
第二次真实请求也出现了,并且返回状态码200
header部分也带上了token:
也就是说,前端装饰上了token的,但是后端没有拿到,所以报错了
最后看看,后端print(request.meta)
因为有两次请求,看看两次到底有什么不同(我已经删除掉了一些无关精要的数据)
第一次请求时:
{'allusersprofile':'run_main': 'true', 'server_name': 'www.xmind.net', 'gateway_interface': 'cgi/1.1', 'server_port': '8000', 'remote_host': '', 'content_length': '', 'script_name': '', 'server_protocol': 'http/1.1', 'server_software': 'wsgiserver/0.2', 'request_method': 'options', 'path_info': '/api/v1/', 'query_string': '', 'remote_addr': '127.0.0.1', 'content_type': 'text/plain', 'http_host': '127.0.0.1:8000', 'http_connection': 'keep-alive', 'http_access_control_request_method': 'get', 'http_origin': 'http://localhost:8080', 'http_user_agent': 'mozilla/5.0 (windows nt 6.1; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/75.0.3738.0 safari/537.36 edg/75.0.107.0', 'http_access_control_request_headers': 'authorization', 'http_accept': '*/*', 'http_referer': 'http://localhost:8080/course', 'http_accept_encoding': 'gzip, deflate, br', 'http_accept_language': 'zh-cn,zh;q=0.9,en;q=0.8,en-us;q=0.7', 'wsgi.input': <_io.bufferedreader name=628>, 'wsgi.errors': <_io.textiowrapper name='<stderr>' mode='w' encoding='utf-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': false, 'wsgi.url_scheme': 'http', 'wsgi.multithread': true, 'wsgi.multiprocess': false, 'wsgi.file_wrapper': <class 'wsgiref.util.filewrapper'>}
第二次请求时:
{'allusersprofile': 'run_main': 'true', 'server_name': 'www.xmind.net', 'gateway_interface': 'cgi/1.1', 'server_port': '8000', 'remote_host': '', 'content_length': '', 'script_name': '', 'server_protocol': 'http/1.1', 'server_software': 'wsgiserver/0.2', 'request_method': 'get', 'path_info': '/api/v1/', 'query_string': '', 'remote_addr': '127.0.0.1', 'content_type': 'text/plain', 'http_host': '127.0.0.1:8000', 'http_connection': 'keep-alive', 'http_accept': 'application/json, text/plain, */*', 'http_origin': 'http://localhost:8080', 'http_authorization': '626d34f7-2302-4bb0-a012-5daf0f588d8c', 'http_user_agent': 'mozilla/5.0 (windows nt 6.1; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/75.0.3738.0 safari/537.36 edg/75.0.107.0', 'http_referer': 'http://localhost:8080/course', 'http_accept_encoding': 'gzip, deflate, br', 'http_accept_language': 'zh-cn,zh;q=0.9,en;q=0.8,en-us;q=0.7', 'wsgi.input': <_io.bufferedreader name=632>, 'wsgi.errors': <_io.textiowrapper name='<stderr>' mode='w' encoding='utf-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': false, 'wsgi.url_scheme': 'http', 'wsgi.multithread': true, 'wsgi.multiprocess': false, 'wsgi.file_wrapper': <class 'wsgiref.util.filewrapper'>}
发现前面一大段都不同,就从请求方式开始有不同的,所以我重新设置了认证组件。
因为一个请求方式是options,一个是get,并且看前端部分,options的时候没有带authorization,终于发现了问题所在,最后在后端做了个判断,当请求方式是options的时候,跳过验证,然后完美解决:
前端请求:没问题,都是200
并且后端确实可以打印出对应的用户名和token:
好的,踩坑记完毕
推荐阅读
-
前后端分离djangorestframework——解决跨域请求
-
前后端分离下用jwt做用户认证
-
20.DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件
-
前后端分离djangorestframework—— 在线视频平台接入第三方加密防盗录视频
-
shiro,基于springboot,基于前后端分离,从登录认证到鉴权,从入门到放弃
-
前后端分离之JWT用户认证
-
前后端分离下用jwt做用户认证
-
ASP .NET + Angular前后端分离实现简单投票系统(JWT登录用户认证)
-
jwt,spring security ,feign,zuul,eureka 前后端分离 整合 实现 简单 权限管理系统 与 用户认证的实现
-
Springboot+Spring Security实现前后端分离登录认证及权限控制的示例代码