利用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 相关文章推荐
Python中的ctime()方法使用教程
May 22 Python
python 的列表遍历删除实现代码
Apr 12 Python
python通过伪装头部数据抵抗反爬虫的实例
May 07 Python
python 识别图片中的文字信息方法
May 10 Python
Win8.1下安装Python3.6提示0x80240017错误的解决方法
Jul 31 Python
用pycharm开发django项目示例代码
Oct 24 Python
在Mac上删除自己安装的Python方法
Oct 29 Python
Python装饰器简单用法实例小结
Dec 03 Python
ipad上运行python的方法步骤
Oct 12 Python
Python 实现训练集、测试集随机划分
Jan 08 Python
python3 使用traceback定位异常实例
Mar 09 Python
PyQt5结合QtDesigner实现文本框读写操作
Jun 11 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
新闻分类录入、显示系统
2006/10/09 PHP
与数据库连接
2006/10/09 PHP
PHP实现通过Luhn算法校验信用卡卡号是否有效
2015/03/23 PHP
浅谈PHP中try{}catch{}的使用方法
2016/12/09 PHP
javascript让setInteval里的函数参数中的this指向特定的对象
2010/01/31 Javascript
JQuery 学习技巧总结
2010/05/21 Javascript
Javascript 类、命名空间、代码组织代码
2011/07/31 Javascript
简单介绍JavaScript数据类型之隐式类型转换
2015/12/28 Javascript
14 个折磨人的 JavaScript 面试题
2016/08/08 Javascript
超详细的JS弹出窗口代码大全
2020/04/18 Javascript
jQuery下拉菜单的实现代码
2016/11/03 Javascript
jQuery使用siblings获取某元素所有同辈(兄弟姐妹)元素用法示例
2017/01/30 Javascript
有关JS中的0,null,undefined,[],{},'''''''',false之间的关系
2017/02/14 Javascript
Vue2.0学习系列之项目上线的方法步骤(图文)
2018/09/25 Javascript
基于js Canvas实现二次贝塞尔曲线
2018/12/25 Javascript
[01:02:38]DOTA2-DPC中国联赛定级赛 LBZS vs Phoenix BO3第二场 1月10日
2021/03/11 DOTA
python中global与nonlocal比较
2014/11/21 Python
python实现类的静态变量用法实例
2015/05/08 Python
在Django框架中编写Contact表单的教程
2015/07/17 Python
python requests 使用快速入门
2017/08/31 Python
matplotlib在python上绘制3D散点图实例详解
2017/12/09 Python
Python API自动化框架总结
2019/11/12 Python
python3中利用filter函数输出小于某个数的所有回文数实例
2019/11/24 Python
python十进制转二进制的详解
2020/02/07 Python
微软俄罗斯官方网站:Microsoft俄罗斯
2016/09/18 全球购物
香港中原电器网上商店:Chung Yuen
2019/06/26 全球购物
香港连卡佛百货官网:Lane Crawford
2019/09/04 全球购物
行政人员岗位职责
2013/12/08 职场文书
信息与计算科学专业推荐信
2014/02/23 职场文书
学生无故旷课检讨书
2014/09/20 职场文书
大学军训的体会
2014/11/08 职场文书
2014年英语教研组工作总结
2014/12/06 职场文书
高中生打架检讨书1000字
2015/02/17 职场文书
2015教师个人师德工作总结
2015/10/23 职场文书
中学音乐课教学反思
2016/02/18 职场文书
Python find()、rfind()方法及作用
2022/12/24 Python