利用Python的装饰器解决Bottle框架中用户验证问题


Posted in Python onApril 24, 2015

首先来分析下需求,web程序后台需要认证,后台页面包含多个页面,最普通的方法就是为每个url添加认证,但是这样就需要每个每个绑定url的后台函数都需要添加类似或者相同的代码,但是这样做代码就过度冗余,而且不利于扩展.

接下来我们先不谈及装饰器,我们都知道Python是个很强大的语言,她可以将函数当做参数传递给函数,最简单的:

def p():
  print 'Hello,world'

def funcfactor(func):
  print 'calling function named', func.__name__
  func()
  print 'end'

funcfactor(p)
# 输出为:
# calling function named p
# Hello,world
# end

一目了然的程序,定义一个函数p(),将函数p当做参数传递给喊出funcfactor,在执行p函数前后加上一些动作.

我们还可以这么做:

def p():
  print 'Hello,world'
def funcfactor(func):
  print 'calling function named', func.__name__
  return func

func = funcfactor(p)
func()
# 输出为:
# calling function named p
Hello,world

正如你看到的,我们可以将函数返回然后赋予一个变量,留待稍后调用.但是这种情况下我们要想在函数执行后做点什么就不可能,但是我们的Python是强大的,Python可以在函数中再嵌套一个函数,我们可以像下面这么做:

def p():
  print 'Hello, world'

def funcfactor(func):
  def wrapper():
    print 'do something at start'
    func()
    print 'do something at end'
  return wrapper

func = funcfactor(p)
func()
#输出为:
# do something at start
# Hello, world
# do something at end

下面我们来看看装饰器,上面的代码虽然实现的一个很困难的任务,但是还不够优雅,而且代码不符合Python的哲学思想,所以装饰器就应声而出,装饰器没有和上面的原理相同,同样用于包装函数,只是代码实现上更加优雅和便于阅读.装饰器以@开头后面跟上装饰器的名称,紧接着下一行就是要包装的函数体,上面的例子用装饰器可用如下方式实现:

def decorator(func):
  def wrapper():
    print 'do something at start'
    func()
    print 'do something at end'
  return wrapper

@decorator
def p():
  print 'Hello, world'

p()
#输出为:
# do something at start
# Hello, world
# do something at end

实际上装饰器并没有性能方面或其他方面的提升,仅仅是一种语法糖,就是上面一个例子的改写,这样更加优雅和便与阅读. 如果我们的p()函数不想仅仅只输Hello,world,我们想向某些我们指定的人打招呼:

def decorator(func):
  def wrapper(*args, **kargs):
    print 'do something at start'
    func(**kargs)
    print 'do something at end'
  return wrapper

@decorator
def p(name):
  print 'Hello', name

p(name="Jim")
#输出为:
# do something at start
# Hello Jim
# do something at end

装饰器在装饰不需要参数的装饰器嵌套函数不是必须得,如果被装饰的函数需要参数,必须嵌套一个函数来处理参数. 写到这里想必大家也知道装饰器的用法和作用.现在回到正题,如何优雅的给后台url加上验证功能?毫无疑问我们使用装饰器来处理:

def blog_auth(func):
  '''
  定义一个装饰器用于装饰需要验证的页面
  装饰器必须放在route装饰器下面
  '''
  # 定义包装函数
  def wrapper(*args, **kargs):
    try:
      # 读取cookie
      user = request.COOKIES['user']
      shell = request.COOKIES['shell']
    except:
      # 出现异常则重定向到登录页面
      redirect('/login')

    # 验证用户数据
    if checkShell(user, shell):
      # 校验成功则返回函数
      return func(**kargs)
    else:
      # 否则则重定向到登录页面
      redirect('/login')
  return wrapper

可以再需要验证的地方添加blog_auth装饰器:

@route('/admin:#/?#')
@blog_auth
def admin():
  '''
  用于显示后台管理首页
  '''
  TEMPLATE['title'] = '仪表盘 | ' + TEMPLATE['BLOG_NAME']
  TEMPLATE['user'] = request.COOKIES['user']
  articles = []
  for article in db.posts.find().sort("date",DESCENDING).limit(10):
    articles.append(article)

  # 将文章列表交给前台模版
  TEMPLATE['articles'] = articles
  return template('admin.html',TEMPLATE)

至此bottle验证的问题就很优雅的用装饰器解决了.

Python 相关文章推荐
11月编程语言排行榜 Python逆袭C#上升到第4
Nov 15 Python
Python学习笔记之open()函数打开文件路径报错问题
Apr 28 Python
Python调用adb命令实现对多台设备同时进行reboot的方法
Oct 15 Python
一文带你了解Python中的字符串是什么
Nov 20 Python
使用python读取.text文件特定行的数据方法
Jan 28 Python
python中break、continue 、exit() 、pass终止循环的区别详解
Jul 08 Python
opencv python Canny边缘提取实现过程解析
Feb 03 Python
浅谈python的elementtree模块处理中文注意事项
Mar 06 Python
在python中使用nohup命令说明
Apr 16 Python
如何用python批量调整视频声音
Dec 22 Python
深度学习详解之初试机器学习
Apr 14 Python
Python数据分析之绘图和可视化详解
Jun 02 Python
在Python中使用mongoengine操作MongoDB教程
Apr 24 #Python
python使用arp欺骗伪造网关的方法
Apr 24 #Python
python使用wxPython打开并播放wav文件的方法
Apr 24 #Python
python使用PyGame播放Midi和Mp3文件的方法
Apr 24 #Python
python使用PyGame绘制图像并保存为图片文件的方法
Apr 24 #Python
python使用PIL缩放网络图片并保存的方法
Apr 24 #Python
python使用Tkinter显示网络图片的方法
Apr 24 #Python
You might like
PHP+Mysql+jQuery实现发布微博程序 php篇
2015/10/15 PHP
WordPress中给媒体文件添加分类和标签的PHP功能实现
2015/12/31 PHP
Yii隐藏URL中index.php的方法
2016/07/12 PHP
PHP生成word文档的三种实现方式
2016/11/14 PHP
PHP实现双链表删除与插入节点的方法示例
2017/11/11 PHP
thinkPHP框架中执行事务的方法示例
2018/05/31 PHP
才发现的超链接js导致网页中GIF动画停止的解决方法
2007/11/02 Javascript
jquery获取ASP.NET服务器端控件dropdownlist和radiobuttonlist生成客户端HTML标签后的value和text值
2010/06/28 Javascript
js中将具有数字属性名的对象转换为数组
2011/03/06 Javascript
通过jQuery源码学习javascript(一)
2012/12/27 Javascript
js 获取和设置css3 属性值的实现方法
2013/05/06 Javascript
js+csss实现的一个带复选框的下拉框
2014/09/29 Javascript
使用Chrome调试JavaScript的断点设置和调试技巧
2014/12/16 Javascript
jQuery中:empty选择器用法实例
2014/12/30 Javascript
js实现滑动触屏事件监听的方法
2015/05/05 Javascript
JavaScript:Date类型全面解析
2016/05/19 Javascript
使用jquery给指定的table动态添加一行、删除一行
2016/10/13 Javascript
js 转json格式的字符串为对象或数组(前后台)的方法
2016/11/02 Javascript
原生JS实现图片翻书效果
2017/02/16 Javascript
node.js实现微信JS-API封装接口的示例代码
2017/09/06 Javascript
基于 Vue 实现一个酷炫的 menu插件
2017/11/14 Javascript
Vue使用vue-draggable 插件在不同列表之间拖拽功能
2020/03/12 Javascript
[05:39]2014DOTA2国际邀请赛 DK晋级胜者组专访战队国士无双
2014/07/14 DOTA
Python实现的递归神经网络简单示例
2017/08/11 Python
Python中利用xpath解析HTML的方法
2018/05/14 Python
django Serializer序列化使用方法详解
2018/10/16 Python
Python中import导入不同目录的模块方法详解
2020/02/18 Python
Python pip install如何修改默认下载路径
2020/04/29 Python
Pandas中两个dataframe的交集和差集的示例代码
2020/12/13 Python
HTML5新特性之用SVG绘制微信logo
2016/02/03 HTML / CSS
美国奢侈品在线团购网站:Gilt City
2017/11/16 全球购物
医学生实习自荐信
2013/10/01 职场文书
2014年业务工作总结
2014/11/17 职场文书
退伍军人感言
2015/08/01 职场文书
医德医风学习心得体会
2016/01/25 职场文书
奖学金发言稿(范文)
2019/08/21 职场文书