完成登陆之后,就会进入后台管理系统的主界面,由于这个是小项目,因此导航菜单所有固化在HTML中,不能修改。通常后台还会有一个欢迎页或关键数据展现的主页面,小项目也没有多大的必要,因此登陆后直接进入公司介绍编辑页面。javascript
首先咱们来看一下公司介绍页面内容html
看上去功能好像很简单,其实咱们要处理的东西仍是挺多的。前端
从页面上看,咱们须要有一个记录读取的接口,来获取公司介绍的内容,并展现在页面上。固然如今数据库里面没有记录存在,因此咱们还须要向数据库的信息表(infomation)中插入一条公司介绍的记录,这样好直接进行编辑(由于公司介绍不会有不少条记录,通常定了后就不会再改变,因此只须要在数据库的信息表里插入一条就能够了)java
另外,从界面上看,咱们还须要有一个上传文件的接口,能够上传图片和文件;还须要一个更新公司介绍内容的接口。python
还有须要修改几个地方,有上传文件,确定须要有下载的接口,因此须要增长一个下载的路由(python与其余语言不同的地方是,全部访问都必须经过路由,因此上传的或放在目录中的文件须要统必定义一个接口来处理,否则用户访问不了,虽然有点麻烦,但这样处理也安全不少,用户上传任何含有木马或程序的文件,它也没法在服务器端执行);nginx配置文件也须要修改一下,增长下载路径规则,这样就能够直接经过nginx访问下载路径了。nginx
向数据库中添加公司介绍记录web
运行pgAdmin连上数据库,而后按第4章的作法,打开sql查询分析器,运行下面代码添加一条数据库记录sql
INSERT INTO infomation(id, title) VALUES (1, '公司介绍');
添加公司介绍记录读取接口数据库
1 @get('/api/about/') 2 def callback(): 3 """ 4 获取指定记录 5 """ 6 sql = """select * from infomation where id = 1""" 7 # 读取记录 8 result = db_helper.read(sql) 9 if result: 10 # 直接输出json 11 return web_helper.return_msg(0, '成功', result[0]) 12 else: 13 return web_helper.return_msg(-1, "查询失败")
由于公司介绍id添加后不会再改变,因此sql语句直接绑死id为1,另外,执行数据库查询之后,返回的是列表,因此返回记录时要加上序号:result[0]json
启动debug(对main.py点击右键=》debug),将用户登陆判断那两行注释掉(否则直接访问会返回-404,“您的登陆已失效,请从新登陆”提示),在浏览器输入:http://127.0.0.1:9090/api/about/就能够看到返回结果(结果的中文字符是unicode编码,须要用站长工具转换一下才能够转为下载效果)
{"msg": "成功", "data": {"content": "", "front_cover_img": "", "id": 1, "title": "公司介绍", "add_time": "2017-10-31 14:17:45"}, "state": 0}
添加公司介绍内容修改接口
1 @put('/api/about/') 2 def callback(): 3 """ 4 修改记录 5 """ 6 front_cover_img = web_helper.get_form('front_cover_img', '图片') 7 content = web_helper.get_form('content', '内容', is_check_special_char=False) 8 # 防sql注入攻击处理 9 content = string_helper.filter_str(content, "'") 10 # 防xss攻击处理 11 content = string_helper.clear_xss(content) 12 13 # 更新记录 14 sql = """update infomation set front_cover_img=%s, content=%s where id=1""" 15 vars = (front_cover_img, content,) 16 # 写入数据库 17 db_helper.write(sql, vars) 18 19 # 直接输出json 20 return web_helper.return_msg(0, '成功')
由于公司介绍只须要一条记录就够了,前面使用手动方式向数据库添加记录,因此代码中咱们就不须要写添加的方法
修改记录使用put方式接收:@put('/api/about/')
从界面图片中能够看到,有文章标题、首页图片和文章内容,由于标题不须要进行修改,因此咱们修改接口只须要处理剩下两项就能够了。
由于提交的内容含有HTML代码,因此使用web_helper.get_form提取值时,须要使用is_check_special_char参数,设置为不检查特殊符号,否则会接收不了。另外接收到参数值之后,咱们须要对它进行防sql注入和防xss处理。
clear_xss()函数是string_helper包新增的清除xss攻击标签用的,它会过滤掉xss的攻击代码。详细代码以下:
def clear_xss(html): """ 清除xss攻击标签 :param html: 要处理的html :return: """ tags = ['a', 'abbr', 'acronym', 'b', 'blockquote', 'code', 'em', 'i', 'li', 'ol', 'strong', 'ul'] tags.extend( ['div', 'p', 'hr', 'br', 'pre', 'code', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'del', 'dl', 'img', 'sub', 'sup', 'u', 'table', 'thead', 'tr', 'th', 'td', 'tbody', 'dd', 'caption', 'blockquote', 'section']) attributes = {'*': ['class', 'id'], 'a': ['href', 'title', 'target'], 'img': ['src', 'style', 'width', 'height']} return bleach.linkify(bleach.clean(html, tags=tags, attributes=attributes))
clear_xss()函数中咱们使用了bleach这个库(须要安装:pip install bleach),它是一个基于白名单、经过转义或去除标签和属性的方式,来对HTML文本净化的python库。
咱们在string_helper_test.py这个测试单元中添加一个测试用例,来测试一下这个函数的使用效果
def test_clear_xss(self): print('-----test_clear_xss------') print(string_helper.clear_xss('<script src="javascript:alert(1);">abc</script>')) print(string_helper.clear_xss('<iframe src="javascript:alert(1);">abc</iframe>')) print(string_helper.clear_xss('<div style="width:0;height:0;background:url(javascript:document.body.onload = function(){alert(/XSS/);};">div</div>')) print(string_helper.clear_xss('<img src = "#"/**/onerror = alert(/XSS/)>')) print(string_helper.clear_xss('<img src = j ava script:al er t(/XSS/)>')) print(string_helper.clear_xss("""<img src = j ava script :a ler t(/xss/)>""")) print(string_helper.clear_xss('<img src="javacript:alert(\'abc\')"></img>')) print(string_helper.clear_xss('<img src="https://www.baidu.com/img/baidu_jgylogo3.gif"></img>')) print(string_helper.clear_xss('<p src="javascript:alert(1);">abc</p>')) print(string_helper.clear_xss("""<input type="text" value="琅琊榜" onclick="javascript:alert('handsome boy')">""")) print(string_helper.clear_xss('<p onclick="javascript:alert("handsome boy")>abc</p>')) print(string_helper.clear_xss('<a href="javascript:alert(1);">abc</a>')) print(string_helper.clear_xss('<a href="/api/">abc</a>')) print(string_helper.clear_xss('<a href="http://www.baidu.com">abc</a>')) print(string_helper.clear_xss('<marquee onstart="alert(/XSS/)">文字</marquee>')) print(string_helper.clear_xss('<div style="" onmouseenter="alert(/XSS/)">文字</div>')) print(string_helper.clear_xss('<li style = "TEST:e-xpression(alert(/XSS/))"></li>')) print(string_helper.clear_xss('<input id = 1 type = "text" value="" <script>alert(/XSS/)</script>"/>')) print(string_helper.clear_xss('<base href="http://www.labsecurity.org"/>')) print(string_helper.clear_xss('<div id="x">alert%28document.cookie%29%3B</div>')) print(string_helper.clear_xss('<limited_xss_point>eval(unescape(x.innerHTML));</limited_xss_point>'))
执行后输出结果:
------ini------ -----test_clear_xss------ <script src="javascript:alert(1);">abc</script> <iframe src="javascript:alert(1);">abc</iframe> <div>div</div> <img src="#"> <img src="j"> <img src="j"> <img> <img src="https://www.baidu.com/img/baidu_jgylogo3.gif"> <p>abc</p> <input onclick="javascript:alert('handsome boy')" type="text" value="琅琊榜"> <p>abc</p> <a>abc</a> <a href="/api/" rel="nofollow">abc</a> <a href="http://www.baidu.com" rel="nofollow">abc</a> <marquee onstart="alert(/XSS/)">文字</marquee> <div>文字</div> <li></li> <input <script="" id="1" type="text" value="">alert(/XSS/)"/> <base href="<a href="http://www.labsecurity.org" rel="nofollow">http://www.labsecurity.org</a>"> <div id="x">alert%28document.cookie%29%3B</div> <limited_xss_point>eval(unescape(x.innerHTML));</limited_xss_point> ------clear------
能够看到,对于富文本编辑器提交的代码,bleach基本知足了咱们的防范xss攻击的处理需求
添加上传接口(PS:咱们使用的文本编辑器是百度的ueditor,由于它没有python的上传处理代码,因此咱们须要动手编辑上传接口,以及html上也要进行对应的修改)
#!/usr/bin/evn python # coding=utf-8 import os from bottle import post, request from common import datetime_helper, random_helper, log_helper @post('/api/files/') def callback(): """ 修改记录 """ # 初始化输出值 result = { "state": "FAIL", "url": "", "title": "上传失败", "original": "" } # 获取上传文件 try: # upfile为前端HTML上传控件名称 upload = request.files.get('upfile') # 若是没有读取到上传文件或上传文件的方式不正确,则返回上传失败状态 if not upload: return result # 取出文件的名字和后缀 name, ext = os.path.splitext(upload.filename) # 给上传的文件重命名,默认上传的是图片 if ext and ext != '': file_name = datetime_helper.to_number() + random_helper.get_string(5) + ext else: file_name = datetime_helper.to_number() + random_helper.get_string(5) + '.jpg' upload.filename = file_name # 设置文件存储的相对路径 filepath = '/upload/' + datetime_helper.to_number('%Y%m%d') + '/' # 组合成服务器端存储绝对路径 upload_path = os.getcwd() + filepath # 若是目录不存在,则建立目录 if not os.path.exists(upload_path): os.mkdir(upload_path) # 保存文件 upload.save(upload_path + upload.filename, overwrite=True) # 设置输出参数(返回相对路径给客户端) result['title'] = result['original'] = upload.filename result['url'] = filepath + upload.filename result['state'] = 'SUCCESS' except Exception as e: log_helper.error('上传失败:' + str(e.args)) # 直接输出json return result
PS:这里只作了上传文件处理,没有上传成功之后存储到数据库中统一管理,若是前端反复上传,会形成服务器存储不少多余文件的问题,你们能够本身发挥想象与动手能力,看看怎么解决这个问题。对于这个问题会在第二部分统一处理。
添加上传文件存储文件夹:直接在项目的要目录下建立upload文件夹
修改main.py文件配置,并建立文件下载路由
导入的bottle库添加response, static_file这两个包,response用于设置输出文件类型为二进制数据传输格式,这样设置后,上传的各类类型文件均可如下载;static_file是使用安全的方式读取文件并输出到客户端
from bottle import default_app, get, run, request, hook, route, response, static_file
在第26行插入下面代码,初始化上传文件存储路径
# 定义upload为上传文件存储路径 upload_path = os.path.join(program_path, 'upload')
添加下载文件访问路由,设置后只要放在upload目录下的文件均可以直接经过浏览器下载
@get('/upload/<filepath:path>') def upload_static(filepath): """设置静态内容路由""" response.add_header('Content-Type', 'application/octet-stream') return static_file(filepath, root=upload_path)
作完以上设置,上传与更新就没有问题了,上传的图片直接使用http://127.0.0.1:9090/upload/xxx.jpg方式就能够访问了,若是想要使用81端口,也就是经过nginx访问,那就须要再配置一下
打开nginx配置文件 :E:\Service\nginx-1.11.5\conf\nginx.conf
将location ~* ^/(index|api)/ 修改成 location ~* ^/(index|api|upload)/
而后在windows任务管理器(键盘同时按Ctrl+Alt+Del键,点击启动任务管理器),找到nginx_service.exe,右键=》结束进程树
从新打开服务(控制面板=》全部控制面板项=》管理工具=》服务),启动nginx_service服务
前端页面相关修改
向/lib/ueditor/1.4.3/目录中添加python文件夹,将添加config.json这个配置项
修改/lib/ueditor/1.4.3/ueditor.config.js 配置项中 服务器统一请求接口路径 为 /api/files/
本文对应的源码包里有ueditor编辑器最新代码(刚刚去百度下载的),去掉了多余的文件,你们可直接删除lib目录里的ueditor这个文件夹,使用源码包里的替换上去就能够了
前端页面的javascript脚本添加了ueditor编辑器初始化、文件上传和表单提交等功能,可直接替换about_edit.html文件,具体你们本身研究一下。
最终效果:
另外,联系咱们的功能与公司介绍差很少,在这里留一下做业给你们本身尝试作一个联系咱们编辑页面出来,下一篇会给联系咱们编辑页面源码给你们
版权声明:本文原创发表于 博客园,做者为 AllEmpty 本文欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然视为侵权。
python开发QQ群:669058475(本群已满)、733466321(能够加2群) 做者博客:http://www.cnblogs.com/EmptyFS/