3.9Django 模板之 Template(2)
早上醒来发现自己丢了东西,却不知是什么东西,找遍房间也没有找到。后来想起那东西叫思念,昨夜梦里我让它去你那儿陪你,莫非还没有回来?
奉上目录,请查阅!
- HTML转义
1.1 会被自动转义的字符
1.2 关闭转义
1.3 字符串字面值 - csrf
2.1 防csrf的使用
2.2 取消保护
2.3 保护原理 - 验证码
3.1 验证码视图
3.2Views视图函数
3.3配置项目url
3.4配置应用url
3.5显示验证码
3.6扩展
3.7验证
3.8第三方
—————————————————————————
1.HTML转义
Django 对字符串进行自动 HTML 转义,如在模板中输出如下值:
视图代码:
def index(request):
return render(request, 'temtest/index2.html',
{
't1': '<h1>hello</h1>'
})
模板代码:
{{t1}}
显示效果如下图:
<h1>hello</h1>
—————————————————————————
1.1 会被自动转义的字符
html 转义,就是将包含的 html 标签输出,而不被解释执行
原因是当显示用户提交字符串时,可能包含一些攻击性的代码,如 js 脚本
Django 会将如下字符自动转义:
< 会转换为<
> 会转换为>
' (单引号) 会转换为'
" (双引号)会转换为 "
& 会转换为 &
当显示不被信任的变量时使用 escape 过滤器,一般省略,因为 Django 自动转义{{t1|escape}}
—————————————————————————
1.2 关闭转义
对于变量使用 safe 过滤器
{{ data|safe }}
对于代码块使用 autoescape 标签
{ % autoescape off %}
{{ body }}
{ % endautoescape %}
标签 autoescape 接受 on 或者 off 参数
自动转义标签在 base 模板中关闭,在 child 模板中也是关闭的
—————————————————————————
1.3 字符串字面值
手动转义
{ { data|default:"<b>123</b>" }}
应写为
{ { data|default:"<b>123</b>" }}
—————————————————————————
2. csrf
全称 Cross Site Request Forgery,跨站请求伪造
某些恶意网站上包含链接、表单按钮或者 JavaScript,它们会利用登录过的用户在浏览器中的认证信息试图在你的网站上完成某些操作,这就是跨站攻击
演示 csrf 如下
建视图 csrf1 用于展示表单, csrf2 用于接收 post 请求
def csrf1(request):
return render(request,'booktest/csrf1.html')
def csrf2(request):
uname=request.POST['uname']
return render(request,'booktest/csrf2.html',{'uname':uname})
配置 url
url(r'^csrf1/$', views.csrf1),
url(r'^csrf2/$', views.csrf2),
创建模板 csrf1.html 用于展示表单
<html>
<head>
<title>Title</title>
</head>
<body>
<form method="post" action="/crsf2/">
<input name="uname"><br>
<input type="submit" value="提交"/>
</form>
</body>
</html>
创建模板 csrf2 用于展示接收的结果
<html>
<head>
<title>Title</title>
</head>
<body>
{{ uname }}
</body>
</html>
将 settings.py 中的中间件代码'django.middleware.csrf.CsrfViewMiddleware'注释
查看 csrf1 的源代码,复制,在自己的网站内建一个 html 文件,粘贴源码,访问查看效果
—————————————————————————
2.1 防csrf的使用
在 django 的模板中,提供了防止跨站攻击的方法,使用步骤如下:
step1:在 settings.py中用'django.middleware.csrf.CsrfViewMiddleware'中间件,此项在创建项目时,默认被启用
step2:在 csrf1.html 中添加标签
<form>
{% csrf_token %}
...
</form>
step3:测试刚才的两个请求,发现跨站的请求被拒绝了
—————————————————————————
2.2 取消保护
如果某些视图不需要保护,可以使用装饰器 csrf_exempt,模板中也不需要写标签,修改 csrf2 的视图如下
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def csrf2(request):
uname=request.POST['uname']
return render(request,'booktest/csrf2.html',{'uname':uname})
运行上面的两个请求,发现都可以请求
—————————————————————————
2.3 保护原理
加入标签后,可以查看源代码,发现多了如下代码
<input type='hidden' name='csrfmiddlewaretoken'
value='nGjAB3Md9ZSb4NmG1sXDolPmh3bR2g59' />
在浏览器的调试工具中,通过 network 标签可以查看 cookie 信息查看跨站的信息,并没有 cookie 信息,即使加入上面的隐藏域代码,发现又可以访问了
结论: django 的 csrf 不是完全的安全
当提交请求时,中间件'django.middleware.csrf.CsrfViewMiddleware'
会对提交的
cookie 及隐藏域的内容进行验证,如果失败则返回 403 错误
—————————————————————————
3. 验证码
在用户注册、登录页面,为了防止暴力请求,可以加入验证码功能,如果验证码错误,则不需要继续处理,可以减轻一些服务器的压力
使用验证码也是一种有效的防止 crsf 的方法
—————————————————————————
3.1 验证码视图
Pillow 的安装
pip install Pillow
详细文档参考 http://pillow.readthedocs.io/en/latest/
https://pypi.python.org/pypi/Pillow/5.0.0
新建 viewsUtil.py,定义函数 verify
Image 表示画布对象
ImageDraw 表示画笔对象
ImageFont 表示字体对象, ubuntu 的字体路径为
“/usr/share/fonts/truetype/freefont”
代码如下:
from django.http import HttpResponse
from PIL import Image,ImageDraw,ImageFont
import random
import io
# Create your views here.
def verify(request):
# 定义变量,用于画面的背景色、宽、高
bg_color = (random.randrange(20,100),random.randrange(20,100),255)
width = 100
height = 25
# 创建画面对象
im = Image.new('RGB',(width,height),bg_color)
# 创建画笔对象
draw = ImageDraw.Draw(im)
# 调用画笔的 point()函数绘制噪点
for i in range(100):
xy = (random.randrange(0,width),random.randrange(0,height))
fill = (random.randrange(0,255),255,random.randrange(0,255))
draw.point(xy,fill=fill)
# 定义验证码的备选值
str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'
# 随机选取 4 个值作为验证码
rand_str=""
for i in range(4):
rand_str = rand_str + str1[random.randrange(0,len(str1)-1)]
print(rand_str)
# 构造字体对象
font = ImageFont.truetype('FZSTK.TTF',23)
# 构造字体颜色
fontcolor = (255,random.randrange(0,255),random.randrange(0,255))
# 绘制 4 个字
draw.text((5,2),rand_str[0],font=font,fill=fontcolor)
draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)
draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)
draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)
# 释放画笔
del draw
# 存入 session,用于做进一步验证
request.session['verifycode'] = rand_str
print(request.session.get('verifycode'))
# 将图片保存在内存中,文件类型为 png
f = io.BytesIO()
im.save(f,'png')
# 将内存中的图片数据返回给客户端, MIME 类型为图片 png
return HttpResponse(f.getvalue(), 'image/png')
—————————————————————————
3.2Views视图函数
def verify_page(request):
verify(request)
template = loader.get_template("verifycode/index.html")
return HttpResponse(template.render())
—————————————————————————
3.3配置项目url
url(r'^',include('verifycode.urls'))
—————————————————————————
3.4配置应用url
在 urls.py 中定义请求验证码视图的 url
url(r"^$",viewsUtil.verify),
—————————————————————————
3.5显示验证码
在模板中使用 img 标签, src 指向验证码视图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>Hello world</div>
<img id='verifycode' src="/verifycode/" alt="CheckCode"/>
</body>
</html>
启动服务器,查看显示成功
—————————————————————————
3.6扩展
新需求:
点击“看不清,换一个” 时,可以换一个新的验证码视图
from django.http import HttpResponse
from django.template import loader
from .viewsUtil import verify
def verify_page(request):
verify(request)
template = loader.get_template("verifycode/index.html")
return HttpResponse(template.render())
def verifycodeValid(request):
vc = request.POST['vc']
if vc.upper() == request.session['verifycode']:
return HttpResponse('ok')
else:
return HttpResponse('no')
应用 url
url(r"^$",views.verify_page),
url(r"^verify/$",views.verify),
url(r'^verifycodeValid/$', views.verifycodeValid),
模版部分
点击事件处理
<script type="text/javascript" src="/static/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(function(){
$('#verifycodeChange').css('cursor','pointer').click(function() {
$('#verifycode').attr('src',$('#verifycode').attr('src')+1)
});
});
</script>
<img id='verifycode' src="/verifycode/?1" alt="CheckCode"/>
<span id='verifycodeChange'>看不清,换一个</span>
说明:
$('#verifycode').attr('src',$('#verifycode').attr('src')+1)
点击后, 点击后就变成了"/verifycode/?11",继续点就会变成"/verifycode/?111"…
?1 是没有实际意义的,它唯一的作用是向浏览器表明: 图片链接发生了变化,图片需要刷新.
添加表单
为了能够实现提交功能,需要增加 form 和 input 标签
<form method='post' action='/verifycodeValid/'>
<input type="text" name="vc">
<img id='verifycode' src="/verifycode/?1" alt="CheckCode"/>
<span id='verifycodeChange'>看不清,换一个</span>
<br>
<input type="submit" value="提交">
</form>
完整的模版代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
<script type="text/javascript" src="/static/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(function () {
$('#verifycodeChange').css('cursor', 'pointer').click(function () {
$('#verifycode').attr('src', $('#verifycode').attr('src') + 1)
});
});
</script>
</head>
<body>
<div>Hello world</div>
<form method='post' action='/verifycodeValid/'>
<input type="text" name="vc">
<img id='verifycode' src="/verify/?1" alt="CheckCode"/>
<span id='verifycodeChange'>看不清,换一个</span>
<br>
<input type="submit" value="提交">
</form>
</body>
</html>
—————————————————————————
3.7验证
接收请求的信息,与 session 中的内容对比
from django.http import HttpResponse
def verifycodeValid(request):
vc = request.POST['vc']
if vc.upper() == request.session['verifycode']:
return HttpResponse('ok')
else:
return HttpResponse('no')
配置验证处理的 url
urlpatterns = [
url(r'^verifycodeValid/$', views.verifycodeValid),
]
—————————————————————————
3.8第三方
可以在网上搜索“验证码” ,找到一些第三方验证码提供网站,阅读文档,使用到项目中。
—————————————————————————
感谢语
每次写到这里的时候,我都会怀疑一下人生,究竟是什么驱使着我向前不停的移动?是爱情吗?不是,是亲情吗?不是,是友情吗?更不是!最后我想明白了,是满身的贫穷,是满心的怕穷!真的!贫穷已经限制了我的想象力!