CSRF的相关处理(跨站请求伪造)
在之前的关于CSRF的相关处理,我们暂时把它关掉了,现在我们来解决这个问题。
我们之前对用CSRF的处理为:
步骤在客户端向后端请求界面数据的时候,后端会往响应中的 cookie 中设置 csrf_token 的值
在 Form 表单中添加单个隐藏的的字段,值也是 csrf_token
在用户点击提交的时候,会带上这两个值向后台发起请求
后端接受到请求,以会以下事件:
从 cookie中取出 csrf_token
从 表单数据中取出来隐藏的 csrf_token 的值进行对比
如果比较之后两值同样,那么代表是正常的请求,如果没取到或者值较不一样,代表不是正常的请求,不执行下一步操作
如果按照上面的做法的话,我们需要在每一个视图函数里加上csrf_token的值以及前端相关的请求必须在from表单里,这样太
麻烦了,我们换个方法来实现。
首先点击我们从flask_wtf 中倒入 的类,然后来到原码进行相关信息的查看这个类的相关信息
中间的大致意思是:
检查表单发送的' ' csrf_token ' '字段,或' ' X-CSRFToken ' '的头部与JavaScript请求发送。
第一种也就是我们上面介绍使用的方法,第二中则是需要对请求头进行修改,来完成相关的设置。
因为是在每次请求之后,我们需要使用到我们flask中的请求钩子,flask中一共有四中请求钩子,这次用到的是@app
.after_request(每次请求之后执行)
下面进行本次使用到的钩子相关补充
@app.after_request # 每次请求后没有异常时调用(视图函数执行完但还未返回响应对象),一般完成响应的加工处理,如设置统一的响应报文,一定要返回加工后的响应对象 def after_request(response): print("after_request") # response.headers['content-type']='application/json' return response
首先我们需要对前端HTML进行修改加入我们的请求头的新相关代码
headers:{'X-CSRFToken':getCookie('csrf_token')}, // 在请求头中带上csrf_tokeny
因为只有为post请求时CSRF才会被执行,所以我们在所有的请求对象为POST的请求中加入
在main.js 中搜索post,然后依次粘贴就行,因为修改了js文件,需要在浏览器中清除掉缓存后再次刷新后才能够完成文件的修改加载。
当完成前端HTML的修改后,因为请求头里的X-CSRFToken是从cookie中直接取值并进行相关的处理,所以我们首先需要生成随机值并保存到cookie中,随机值的生成需要使用flask中生成函数来进行,并通过这个函数来完成校验的相关操作,因为我们这里不能在后端存入值来进行对比校验,这里请求头的值是直接从cookie中来取的,每一次新的请求cookie的值会变请求头的
值也会随着cookie的值一起变化,它们使用的是同一次生成的值,所以并不能进行对比然后完成校验,相关的校验需要通过flask自己来完成。
首先导包:
导入的是生成随机值的函数,而且这个函数只能依托于视图函数来使用,不能单独进行数据的生成,如果单独使用的话会报错
我们将在我们 的请求钩子中使用它,先创建对应的函数然后用请求钩子装饰
然后使用我们导入的generate_csrf函数来生成我们的随机值并用变量保存下来
然后将我们接收到到的相应对象里进行写入cookie的操作然后再把修改后的相应对象返回出去
因为我们需要使用到app,所以函数的位置在我们的生成app函数内,也就是info的__init__文件里
@app.after_request def after_request(response): csrf_token = generate_csrf() # print(csrf_token) response.set_cookie("csrf_token",csrf_token) return response
完成之后先进行测试,首先是请求钩子能不能正常执行,我们将我们生成的随机值打印验证一下,每一次的请求后执行,首先进入主页后查看控制
台是否对随机值进行了打印
请求钩子的执行没问题后将我们之前CSRF的注释解开,然后操作有post请求的功能,查看有无报错,
如果没有报错并正常执行,我们的问题就处理完了
前端新闻点击排行的渲染
首先来到我们的前端关于点击排行这一块的展示页面进行分析我们需要处理的数据有哪些
首先我们需要渲染的新闻数据是6条,渲染的内容为新闻的标题,相关的排序
处理是通过新闻的点击量来完成的,并对前三条的序号有不同的处理,后面的一样
下面我们来依次进行处理
首先这一块的代码是关于首页的渲染,所以我们来到首页渲染的视图中进行修改
还是先写文档注释,在我们上次关于获取登录状态的后面进行添加描写
我们获取到点击量最多的新闻数据后也需要生成上下文并给到前端页面进行渲染,所以这里修改了一下生成上下文的步骤顺序,改为每次都需要查询数据的步骤之后
代码的实现:
#2点击排行新闻处理 news_click_list = [] #空的列表 #2.1通过查询数据库获得点击量对多的前6条数据 try: news_click_list = News.query.order_by(News.clicks.desc()).limit(6) except Exception as e : current_app.logger.error(e) #生成保存用户变量的上下文并传到前台进行相关判断处理 context={ "user":user, "news_click_list":news_click_list } return render_template("news/index.html",**context)
这里使用的查询方法记住就可以了,order_by是按照对应字段从小到大的顺序来进行获取,然后我们通过.desc()来进行翻转,也就是从大到小,然后limit来获取取得数据的数量,也就是
前6条,然后因为是第三方数据库的操作,需要进行异常捕捉并进行相关的处理,还有因为是放在try里取得的新闻变量,所以需要先设置默认值,。不然生成上下文时会报错,参考登录状态时设置上下文时 的
操作,设置好之后前台就可以进行相关渲染了,还有这里设置的默认值为空的列表,不能为None ,因为前台要进行取值操做
完成之后通过for遍历来完成相关的渲染
来到我们index.html中,找到对应的代码块并进行修改
这里展示的内容就不在是固定的了,所以先将之前的代码注释掉,然后用jinja2模板引擎的写法来进行相关代码的编写
首先我们需要在for循环里面进行,通过对传入带前台的前6个新闻数据进行遍历然后进行相关代码的编写
首先展示的内容需要更改,不再是固定的内容,需要是获取到的新闻数据的标题,
然后序号也是随着循环进行变化的,这里使用了模板引擎自带的功能来完成,也就是获取当前循环次数的代码来完成
loop除了index之外还有其他的功能
完成内容和序号的渲染之后我们需要对前三条的序号进行单独的处理
这里就要使用到我们的过滤器来完成
首先在后台来完成自定义过滤器的编写,首先在我们存放工具的文件夹utils 中新建一个叫comment的Python文件来存放我们
自定义的工具比如过滤器,
然后进行自定义过滤器代码的编写,过滤器本身是函数,所以我们首先创建一个函数
然后进行相关处理:
def do_rank(index): if index == 1: return "first" elif index == 2: return "second" elif index == 3: return "third" else: return ""
我们只需要在<li>标签的class中返回不同的值就可以完成序号展示的处理了,所以我们根据存入的值设置不同的返回值就可以完成过滤器的编写,这里只对前
3次循环进行不同值返回的设置,后面的不变设置为空就完成了。这里传入的值就是每次的循环次数。也就是loop.index的值
完成之后还需要在app中进行自定义过滤器的添加,我们也放在代码的后面防止加载的问题,这里放在蓝图的后面就行。
首先在info的__init__中导入,然后配置到app中
完成之后我们再次完成主页进行查看就可以了,校验的话查看可视化数据看一下点击排行的最多的前6条新闻的
标题是不是展示的 标题就可以了,序号的话直接就可以看到,你也可以通过修改点击量看是不是会对展示的标题
进行修改。
修改前:
修改后:
好了,这样我们对新闻排行的相关渲染也完成了。