利用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 threading多线程编程实例
Sep 18 Python
使用pyecharts无法import Bar的解决方案
Apr 23 Python
Python语言进阶知识点总结
May 28 Python
Django Aggregation聚合使用方法解析
Aug 01 Python
使用Django搭建web服务器的例子(最最正确的方式)
Aug 29 Python
浅谈tensorflow中Dataset图片的批量读取及维度的操作详解
Jan 20 Python
Python实现汇率转换操作
May 03 Python
opencv之颜色过滤只留下图片中的红色区域操作
Jun 05 Python
python语言是免费还是收费的?
Jun 15 Python
浅析Python面向对象编程
Jul 10 Python
selenium学习教程之定位以及切换frame(iframe)
Jan 04 Python
python os.listdir()乱码解决方案
Jan 31 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 中使用随机数的三个步骤
2006/10/09 PHP
提高PHP编程效率的53个要点(经验小结)
2010/09/04 PHP
简单的php写入数据库类代码分享
2011/07/26 PHP
PHP HTML JavaScript MySQL代码如何互相传值的方法分享
2012/09/30 PHP
php采集神器cURL使用方法详解
2016/02/19 PHP
PHP检测数据类型的几种方法(总结)
2017/03/04 PHP
js加入收藏以及使用Jquery更改透明度
2014/01/26 Javascript
seajs中模块的解析规则详解和模块使用总结
2014/03/12 Javascript
JavaScript版的TwoQueues缓存模型
2014/12/29 Javascript
JS模拟并美化的表单控件完整实例
2015/08/19 Javascript
JavaScript与jQuery实现的闪烁输入效果
2016/02/18 Javascript
基于gulp合并压缩Seajs模块的方式说明
2016/06/14 Javascript
js 实现数值的千分位及保存小数方法(推荐)
2016/08/01 Javascript
使用vue构建一个上传图片表单
2017/07/04 Javascript
利用yarn代替npm管理前端项目模块依赖的方法详解
2017/09/04 Javascript
打造通用的匀速运动框架(实例讲解)
2017/10/17 Javascript
vue 双向数据绑定的实现学习之监听器的实现方法
2018/11/30 Javascript
layui table 多行删除(id获取)的方法
2019/09/12 Javascript
JavaScript使用canvas绘制随机验证码
2020/02/17 Javascript
vue设置默认首页的操作
2020/08/12 Javascript
python基础教程之类class定义使用方法
2014/02/20 Python
Django中的Model操作表的实现
2018/07/24 Python
python实现n个数中选出m个数的方法
2018/11/13 Python
阿根廷票务网站:StubHub阿根廷
2018/04/13 全球购物
Myprotein意大利官网:欧洲第一运动营养品牌
2018/11/22 全球购物
中国汽车租赁行业头部企业:一嗨租车
2019/05/16 全球购物
经济职业学院毕业生自荐书
2014/03/17 职场文书
六一儿童节演讲稿
2014/05/23 职场文书
住房租房协议书
2014/08/20 职场文书
学雷锋献爱心倡议书
2015/04/27 职场文书
贴吧吧主申请感言
2015/08/03 职场文书
2016年员工年度考核评语
2015/12/02 职场文书
创业计划书之书店
2019/09/10 职场文书
HTML通过表单实现酒店筛选功能
2021/05/18 HTML / CSS
浅谈MySQL 亿级数据分页的优化
2021/06/15 MySQL
mysql 数据插入优化方法之concurrent_insert
2021/07/01 MySQL