利用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实现的ini文件操作类分享
Nov 20 Python
Python常用随机数与随机字符串方法实例
Apr 09 Python
简单介绍Python中的try和finally和with方法
May 05 Python
在SAE上部署Python的Django框架的一些问题汇总
May 30 Python
简单易懂的python环境安装教程
Jul 13 Python
Python基于回溯法子集树模板解决野人与传教士问题示例
Sep 11 Python
Python中偏函数用法示例
Jun 07 Python
python 获取utc时间转化为本地时间的方法
Dec 31 Python
Pycharm 字体大小调整设置的方法实现
Sep 27 Python
python的scipy实现插值的示例代码
Nov 12 Python
Matplotlib.pyplot 三维绘图的实现示例
Jul 28 Python
python快速安装OpenCV的步骤记录
Feb 22 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
叶罗丽:为什么大家对颜冰这对CP非常关心,却对金茉两人十分冷漠
2020/03/17 国漫
非洲第一个咖啡超凡杯大赛承办国—卢旺达的咖啡怎么样
2021/03/03 咖啡文化
如何把PHP转成EXE文件
2006/10/09 PHP
浅析PHP中Collection 类的设计
2013/06/21 PHP
解析CI的AJAX分页 另类实现方法
2013/06/27 PHP
Yii 访问 Gii(脚手架)时出现 403 错误
2018/06/06 PHP
B/S开发中常用javaScript技术与代码
2007/03/09 Javascript
基本jquery的控制tabs打开的数量的代码
2010/10/17 Javascript
jQuery学习笔记 更改jQuery对象
2012/09/19 Javascript
javascript中cookie对象用法实例分析
2015/01/30 Javascript
JavaScript实现定时隐藏与显示图片的方法
2015/08/06 Javascript
jQuery实现点击任意位置弹出层外关闭弹出层效果
2016/10/19 Javascript
js print打印网页指定区域内容的简单实例
2016/11/01 Javascript
ionic2中使用自动生成器的方法
2018/03/04 Javascript
ES6 Iterator接口和for...of循环用法分析
2019/07/31 Javascript
js实现简单扫雷
2020/11/27 Javascript
JS中多层次排序算法的实现代码
2021/01/06 Javascript
python开发之for循环操作实例详解
2015/11/12 Python
Python列表list内建函数用法实例分析【insert、remove、index、pop等】
2017/07/24 Python
Python生成器定义与简单用法实例分析
2018/04/30 Python
手把手教你如何安装Pycharm(详细图文教程)
2018/11/28 Python
Python3实现英文字母转换哥特式字体实例代码
2020/09/01 Python
Python内存泄漏和内存溢出的解决方案
2020/09/26 Python
Html5 实现微信分享及自定义内容的流程
2019/08/20 HTML / CSS
HTML5 Canvas概述
2009/08/26 HTML / CSS
Europcar英国:英国汽车和货车租赁
2017/01/21 全球购物
亿阳信通股份有限公司笔试题(C#)
2016/03/04 面试题
高级销售员求职信
2013/10/25 职场文书
中国入世承诺
2014/04/01 职场文书
暑假学习心得体会
2014/09/02 职场文书
2014党员学习习主席讲话思想汇报
2014/09/15 职场文书
保密工作整改报告
2014/11/06 职场文书
仓库保管员岗位职责
2015/02/09 职场文书
入学证明
2015/06/23 职场文书
篮球赛新闻稿
2015/07/17 职场文书
《狼牙山五壮士》教学反思
2016/02/17 职场文书