#TCP,HTTP通讯协议 Response、Request库 Cookie、Session、Token会话工具 crfs
HttpRequest
服务器在接受到http请求后,会根据报文创建httprequest对象,视图中第一个参数就是httprequest对象
django框架会进行自行包装,之后床底给视图
request
属性
path:请求的完整路径
method:请求的方法
encoding:编码方式
GET:类似字典参数,包含了get的所有参数
POST:类似该带你的参数,包含了post所有参数
###FILES:类似字典的参数,包含看上传的文件:
会话技术
解决度武器如何识别客户端的问题
http在web开发中基本都是短链接即从request开始response结束
一、Cookie
客户端技术,将数据信息存储到浏览器中,存储的结构是字典结构,即key-value.
Cookie是服务端创建,但保存于客户端,客户端每次发送请求时都会将Cookie信息发送到服务器(因为Cookie是请求头信息的一部分)
Cookie不支持中文,不能跨浏览器,不能跨域名
1、设置cookie
set_cookie(key, value=’’, max_age=None, expires=None, path=’/’, domain=None, secure=None, httponly=False)
set_signed_cookie(key, value, salt=’’, max_age=None, expires=None, path=’/’, domain=None, secure=None, httponly=True)设置加密的cookie,salt是秘钥
key: cookie的name
value:cookie的值
max_age:cookie存活时间,单位是秒
expires:具体过期时间
path:cookie的访问路径,只有在某个路径下访问
domain:域名,只有在某个域名下访问
secure:安全
httpoly:如果为True那么js就不能获取cookiemax-age 有效时长,单位为秒,指定为0,表示关闭浏览器失效(默认)指定为有效数值100表示100秒后自动失效,设置为None永不过期
expires 支持一个datetime或timedelta,可以指定一个具体的日期,expires=timedelta(days=10)表示十天后过期
max-age和xepires两个指定一个
# 普通设置,以明文的方式显示 def setcookie(request): response = HttpResponse('设置COOKIE成功') response.set_cookie('name','egon') return response
#加盐设置,以加密的形式显示 def do_login(request): uname = request.POST.get('uname') response = HttpResponseRedirect(reverse('app:mine')) # response.set_cookie('uname', uname, max_age=60) response.set_signed_cookie('content', uname, "Rock") return response
2、获取
HttpRequest.COOKIES.get(key)
request.get_signed_cookie(“cookie名称”,salt=“盐”)
def getcookie(request): return HttpResponse(request.COOKIES.get('name'))
def mine(request): # uname = request.COOKIES.get("content") try: uname = request.get_signed_cookie("content", salt="Rock") if uname: # return HttpResponse(uname) return render(request, 'mine.html', context={"uname": uname}) except Exception as e: print("获取失败") return redirect(reverse('app:login'))
3、删除
response.delete_cookie(key)
def logout(request): response = redirect(reverse("app:login")) response.delete_cookie("content") return response
二、Session
Session是用来表示一个用户与服务端的一次“会话”。使用客户端发送的sessionid(存在与Cookie中)与服务端的sessionid匹配,找到客户端请求所属的“会话”,经常用于登录验证。
Session一般保存在内存中,在Django中,Session默认使用数据库保存,若想变更Session的保存方式,需要添加SESSION_ENGINE配置信息,可以将session保存到redis中。
Django 默认 Session 数据保存到数据库中,可以在 settings.py 中看到配置信息项目。
INSTALLED_APPS = [ # 启用 sessions 应用 'django.contrib.sessions', ] MIDDLEWARE = [ # 启用 Session 中间层 'django.contrib.sessions.middleware.SessionMiddleware', ]
除了上述的基于数据库的会话,Django 还提供另外三种方法:
1)保存到缓存中
如果你的场景需要快速存储会话,可以选择该方案。使用之前,需要配置下 Django 的缓存框架。在 settings.py 中增加 SESSION_ENGINE 配置。这其中也是有两种保存数据的方案,具体配置如下:
- 方案一
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
这种配置方案 Django 只是简单保存会话。同时,这种方案持久性不好。因为当缓存数据存满时将清除部分数据,或者遇到缓存服务器重启时数据将丢失。
- 方案二
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
这种方案既保证快速存储会话数据,又保证数据持久性。因为该使用方案, Session 在保存到缓存的同时还会被保存到数据库中,当 Django 在缓存中找不到Session 时,会从数据库中找到。因此,这种方案的性能开销会比方案一大。
如果我们在工程中同时配置了数据库会话和缓存会话,Django 默认优秀选择缓存会话。
2)保存到文件中
这种方案是保存数据到本地磁盘中。因为磁盘的 I/O 瓶颈问题,导致这种方案存储数据效率不是很高。如果要使用这种方案,在 settings.py 中增加 SESSION_ENGINE 配置。具体配置如下:SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 可选配置 SESSION_FILE_PATH = '/monkey/www/'
SESSION_FILE_PATH 默认使用 tempfile.gettempdir() 方法的返回值,就像 /tmp目录。如果你想更新文件的保存路径,可以手动指定。另外需确保你的文件存储目录,以及 Web 服务器对该目录具有读写权限。
1、存储数据
HttpRequest.session[key] = value,数据进行了base64编码
2、读取数据
request.session.session_key 获取session_id
HttpRequest.session.get(key)
3、删除session
del request.session[“key”]
request.session.flush() 同时清除cookie和session
request.session.clear() 清除所有session
def login(request): if request.method == "GET": return render(request, 'two_login.html') elif request.method == "POST": username = request.POST.get("username") request.session["username"] = username return HttpResponse("登录成功") def mine(request): username = request.session.get("username") print(request.session.session_key) return render(request, 'two_mine.html', context=locals()) def logout(request): response = redirect(reverse('myapp:mine')) # del request.session['username'] # response.delete_cookie('sessionid') # session cookie一起干掉 request.session.flush() return response
4、session重要配置
①、SESSION_EXPIRE_AT_BROWSER_CLOSE = True
当浏览器关闭时,清除本地Cookie
②、 SESSION_COOKIE_AGE = 60
设置session保存的秒数
5、扩展:将session保存到redis
①安装django-redis-sessions库
pip install django-redis-sessions
②在settings.py中配置
SESSION_ENGINE = 'redis_sessions.session' SESSION_REDIS = { 'host':'127.0.0.1', 'port':6379, 'db':0, 'password':'Redis密码', 'prefix':"key前缀", 'socket_timeout':5 }
三、Token
会话技术
自定义session
数据存储在服务器中
如果web网站开发中,效果基本等同与session
主要应用场景时在移动端和专用客户端开发中,不支持session的设备中
Token是为了弥补服务端会话技术的缺点(占用服务器资源)而产生的,Token验证的思想是“以时间换空间”.
当第一次验证成功(用户名和密码正确),服务端对用户数据进行签名生成一个token,并将该token发送到客户端,当客户端发送请求时,会携带该token到服务器端,服务端对该token进行解密验证,当验证成功,则说明用户验证通过,否则验证失败.
1、基本算法
①MD5摘要算法
用来验证数据完整性 ,单向不可逆,防爆破性高,统一输出,默认输出128位的二进制,32位的16进制使用hexdigest()
import hashlib md5 = hashlib.md5() md5.update('xxx'.encode()) crypto_str = md5.hexdigest()
②应用
基本时间+随机数生成MD5的32位字符串
import hashlib import random import time m = hashlib.md5() m.update(str(time.time()+ random.random()).encode()) a = m.hexdigest()
2、使用方式
①使用在移动端或客户端开发中,通常以Json形式传输,需要移动端自己存储Token,需要获取Token关联数据的时候,主动传递Token
def login(request): if request.method == "GET": return render(request, 'two_login.html') elif request.method == "POST": username = request.POST.get("username") m = hashlib.md5() m.update(str(time.time()+ random.random()).encode()) token = m.hexdigest() data = { 'status': 200, 'username': username, 'token': token # 设置token } return JsonResponse(data) def mine(request): # 客户端访问时候需要带上token # http://127.0.0.1:8000/myapp/mine/?token=e912be747de3c51f11e9e9bea72b49bf token = request.GET.get('token') if token: return JsonResponse({ 'status': 'OK' })
②在web开发中,Token和session类似,携带在cookie中。
def login(request): if request.method == 'GET': return render(request, 'login.html') else: name = request.POST.get('name') pwd = request.POST.get('pwd') users = User.objects.filter(name=name,pwd=pwd) if users: user = users.first() token = str(time.time()) user.token = token user.save() response = HttpResponse('<h3 style="color:green">登录成功</h3>') response.set_cookie('token',token) # 将token也保存于响应对象,发送给客户端 return response else: return HttpResponse('用户名或密码错误') def mine(request): token = request.COOKIES.get("token") if token: user = User.Objects.get(token=token) return HttpResponse('登录成功')
四、三者对比
Cookie使用更简洁,服务器压力更小,数据不是很安全
Session服务器要维护Session,相对安全
Token拥有Session的所有优点,自己维护略微麻烦,支持更多的终端
def hello_request(request): #拿到request请求重的所有东西 print(request.META) #拿到IP地址 print(request.META.get('REMOTE_ADDR')) print(request) print(request.path) print(request.GET) #hobby = request.GET.get('') # hobby = request.GET.getlist('') print(request.POST) print(request.method) return HttpResponse('request success')
{'__INTELLIJ_COMMAND_HISTFILE__': '/Users/manblue/Library/Preferences/PyCharm2019.3/terminal/history/history-2', 'TERMINAL_EMULATOR': 'JetBrains-JediTerm', 'HOME': '/Users/manblue', 'COMMAND_MODE': 'unix2003', 'LOGIN_SHELL': '1', 'XPC_SERVICE_NAME': '0', 'LOGNAME': 'manblue', 'TMPDIR': '/var/folders/94/1trp44117rz9wf0jzp6x615w0000gp/T/', 'SHELL': '/bin/zsh', 'SECURITYSESSIONID': '186a7', 'XPC_FLAGS': '0x0', 'ZDOTDIR': '', 'LaunchInstanceID': '972D8045-030C-4AAF-B13E-620C3252BA32', 'LC_CTYPE': 'zh_CN.UTF-8', '__CF_USER_TEXT_ENCODING': '0x1F6:0x19:0x34', 'USER': 'manblue', 'PATH': '/Users/manblue/venv/django/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/VMware Fusion.app/Contents/Public', 'TERM': 'xterm-256color', 'SSH_AUTH_SOCK': '/private/tmp/com.apple.launchd.Dl0sfJnVxE/Listeners', 'SHLVL': '1', 'PWD': '/Users/manblue/PycharmProjects/django/django_01', 'OLDPWD': '/Users/manblue', 'VIRTUAL_ENV': '/Users/manblue/venv/django', 'PS1': '(django) %n@%m %1~ %# ', '_': '/Users/manblue/venv/django/bin/python', 'DJANGO_SETTINGS_MODULE': 'django_01.settings', 'TZ': 'Asia/Chongqing', 'RUN_MAIN': 'true', 'SERVER_NAME': '1.0.0.127.in-addr.arpa', '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': '/study/hellorequest/', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15', 'HTTP_ACCEPT_LANGUAGE': 'zh-cn', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate', 'HTTP_CONNECTION': 'keep-alive', 'wsgi.input': <_io.BufferedReader name=5>, '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'>} None <WSGIRequest: GET '/study/hellorequest/'> /study/hellorequest/ <QueryDict: {}> <QueryDict: {}> GET
方法
is_ajax():判断时候是ajax(),通常用在移动端的js中
CSRF(Cross Site Request Forgery)
https://blog.youkuaiyun.com/qq_41000891/article/details/82784489
防止跨站攻击
防止恶意注册,确保客户端是我们自己的客户端
是用来cookie 中的csrftoken进行验证传输
服务器发送给库护短,客户端将cookie获取过来,还要进行编码转化(数据安全)
也就是跨站请求伪造,实现的原理是CSRF攻击者在用户已经登录目标网站之后,诱使用户访问一个攻击页面,利用目标网站对用户的信任,以用户身份在攻击页面对目标网站发起伪造用户操作的请求,达到攻击目的;
2.CSRF认证
- 在项目的settings文件中有一个配置项MIDDLEWARE,表示默认Django启用csrf认证;
'django.middleware.csrf.CsrfViewMiddleware'
- 当页面为form表单提交时,一般都需要在form标签中加上
{% csrf_token %}
,如果第一次表单提交的时候带上了csrf_token
,服务器端就会认为这个是可信任的用户,所以如果第二次提交时form表单去掉csrf_token
,但是浏览器请求时会带上之前表单第一次提交时中的csrf_token
,服务器端默认信任这个csrf_token
;<form action="{% url 'users:image' %}" method="post" enctype="multipart/form-data"> {# <input type="file" name="upload" accept="image/gif, image/jpeg, image/png, image/jpg">#} <input type="file" name="upload"> <input type="submit" value="提交"> {% csrf_token %} </form>
- 如果在settings文件中将csrf的中间件注释,那么form表单提交,将不再需要csrf token认证;
3.CSRF局部禁用
- 为了避免没有csrf token而产生的403的forbidden错误问题,通常使用
django.views.decorators.csrf.csrf_exempt
装饰器来修饰这个处理POST请求的View, 这种方式是CSRF局部禁用;from django.views.generic import View from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt class CSRFTestView(View): @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) def post(self, request): pass
- 局部启用可以使用
csrf_protect
,需要先在settings文件注释CsrfViewMiddleware
;from django.views.generic import View from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_protect class CSRFTestView(View): @method_decorator(csrf_protect) def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) def post(self, request): pass
- 如果需要禁用Django CSRF功能项目都是启用全局的CSRF中间件,针对局部的View进行禁用;
4.Postman
Postman是一种网页调试与发送网页http请求的chrome插件,可以用来很方便的模拟get、post、put、patch、delete、copy等多种方式的请求来调试接口;
postman可用作macOS,Windows和Linux操作系统的本机应用程序。Windows系统下安装postman只需要下载安装文件,然后运行安装程序就可以了;算法
编码解码
base64
urlencode
摘要算法,指纹算法,杂凑算法
MD5 SHA
MD5
MD5的全称是Message-Digest Algorithm 5(信息-摘要算法)。128位长度。目前MD5是一种不可逆算法。具有很高的安全性。它对应任何字符串都可以加密成一段唯一的固定长度的代码。
SHA1
SHA1的全称是Secure Hash Algorithm(安全哈希算法) 。SHA1基于MD5,加密后的数据长度更长,它对长度小于264的输入,产生长度为160bit的散列值。比MD5多32位。因此,比MD5更加安全,但SHA1的运算速度就比MD5要慢了。
Python 中的用法:
Python 内置的 hashlib 模块就包括了 md5 和 sha1 算法。而且使用起来也极为方便
Example of MD5:
1 import hashlib 2 3 data = 'This a md5 test!' 4 hash_md5 = hashlib.md5(data) 5 6 hash_md5.hexdigest()
会输出:
1 '0a2c0b988863f08471067903d8737962'
上面这段字符串就是 data 转换后的MD5值。
MD5不仅仅是上面这个例子这样用来处理字符串,还有更广泛的用途:
- 加密网站注册用户的密码。
- 网站用户上传图片 / 文件后,计算出MD5值作为文件名。(MD5可以保证唯一性)
- key-value数据库中使用MD5值作为key。
sha1的使用与MD5类似,就像下面这样,所以不再讲解SHA1:
import hashlib hashlib.sha1('This is a sha1 test!').hexdigest()
单向不可逆
不管输入多长,输出都是固定长度
只要输入有任意的变更,输出都会发生巨大的变化
加密算法
对称加队
一把钥匙
DES AES
python3.6库安装:pip3 install pycryptodome。
但是一旦钥匙丢了就遭了
非对称加密
两把钥匙,成对的
公钥和私钥
安全性最高
算法复杂,需要时间长
支付宝,微信都是RSA
response
服务器返回给客户端的数据
摘要 URL: http://127.0.0.1:8000/study/hellojsonresponse/ 状态: 200 OK 来源: 网络 地址: 127.0.0.1:8000 请求 GET /study/hellojsonresponse/ HTTP/1.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Upgrade-Insecure-Requests: 1 Host: 127.0.0.1:8000 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15 Accept-Language: zh-cn Accept-Encoding: gzip, deflate Connection: keep-alive 响应 HTTP/1.1 200 OK Date: Fri, 27 Mar 2020 10:11:33 GMT Content-Length: 28 Content-Type: application/json X-Frame-Options: SAMEORIGIN Server: WSGIServer/0.2 CPython/3.7.4
httpresponse:由我们自己创建
属性
content 返回的内容
charset 编码格式
status_code 响应状态码
content_type MIME类型
METE
作用:制定传输数据使用那种形式打开
格式:大类型/小类型 eg:image/
https://baike.baidu.com/item/MIME/2900607?fr=aladdin
方法
Init 初始化内容
write(xxx) 直接写出文本
flush() 冲刷缓冲区
set_cookie(key,value=‘xxx’,max_age=None,exprise=None) 设置cookie
delete_cookie(key) 删除cookie
httpresponse子类
HttpResponseRedict
相应重定向:可以实现服务器内部跳转
暂时性的重定向
return HttpResponseRedict(‘/grade/2017’)
使用的时候推荐使用反响解析
####JsonResponse
以json格式返回数据
在把数据创诶移动端或者给ajax的时候一般需要用json
返回json数据的请求,通常用在异步 请求上
JsonResponse(dict)
json简介
https://www.jianshu.com/p/1970a209672f
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它基于JavaScript的一个子集,易于人的编写和阅读,也易于机器解析。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。 这些特性使JSON成为理想的数据交换语言。
对象是一个无序键值对的集合,以"{“开始,同时以”}“结束,键值对之间以”:“相隔,不同的键值对之间以”,"相隔,举例
{ "key1" : 1, "key2" : "string" }
####HttpResponsePermanentRedirect
重定向,永久性
301
HttpResponseBadRequest
400
HttpResponseNotFound
404
HttpResponseForbidden
403
HttpResponseNotAllowed
405
HttpResponseServerError
500
Http404
Exception
Raise 主动抛异常
###掌握Shell自动化运维脚本的开发及采用脚本完成日志的清洗。