利用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 相关文章推荐
flask中主动抛出异常及统一异常处理代码示例
Jan 18 Python
python正则表达式面试题解答
Apr 28 Python
对numpy Array [: ,] 的取值方法详解
Jul 02 Python
使用Python更换外网IP的方法
Jul 09 Python
解决python xlrd无法读取excel文件的问题
Dec 25 Python
python实现可变变量名方法详解
Jul 01 Python
解决Django加载静态资源失败的问题
Jul 28 Python
python实现单目标、多目标、多尺度、自定义特征的KCF跟踪算法(实例代码)
Jan 08 Python
python中数字是否为可变类型
Jul 08 Python
Python中bisect的用法及示例详解
Jul 20 Python
Python如何解除一个装饰器
Aug 07 Python
python爬虫快速响应服务器的做法
Nov 24 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 操作数组(合并,拆分,追加,查找,删除等)
2012/07/20 PHP
使用PHP实现阻止用户上传成人照片或者裸照
2014/12/25 PHP
Zend Framework教程之Zend_Form组件实现表单提交并显示错误提示的方法
2016/03/21 PHP
将CKfinder整合进CKEditor3.0的新方法
2010/01/10 Javascript
基于jquery中children()与find()的区别介绍
2013/04/26 Javascript
jQuery解决下拉框select设宽度时IE 6/7/8下option超出显示不全
2013/05/27 Javascript
JavaScript中setAttribute用法介绍
2013/07/20 Javascript
原生Javascript封装的一个AJAX函数分享
2014/10/11 Javascript
javascript中HTMLDOM操作详解
2014/12/11 Javascript
javascript跨域的方法汇总
2015/10/23 Javascript
Jquery效果大全之制作电脑健康体检得分特效附源码下载
2015/11/02 Javascript
jQuery实现CheckBox全选、全不选功能
2017/01/11 Javascript
JS利用正则表达式实现简单的密码强弱判断实例
2017/06/16 Javascript
Vue如何实现响应式系统
2018/07/11 Javascript
快速解决bootstrap下拉菜单无法隐藏的问题
2018/08/10 Javascript
Vue项目自动转换 px 为 rem的实现方法
2018/10/29 Javascript
vue实现双向绑定和依赖收集遇到的坑
2018/11/29 Javascript
浅谈Javascript中的对象和继承
2019/04/19 Javascript
ckeditor一键排版功能实现方法分析
2020/02/06 Javascript
Python模拟登陆淘宝并统计淘宝消费情况的代码实例分享
2016/07/04 Python
解决python中使用plot画图,图不显示的问题
2018/07/04 Python
浅谈在JupyterNotebook下导入自己的模块的问题
2020/04/16 Python
使用css3实现超炫的loading加载动画效果
2014/05/07 HTML / CSS
使用CSS3来代替JS实现交互
2017/08/10 HTML / CSS
Sam’s Club山姆会员商店:沃尔玛旗下高端会员制商店
2017/01/16 全球购物
自荐信格式范文
2013/10/07 职场文书
庆七一活动方案
2014/01/25 职场文书
财务部经理岗位职责
2014/02/03 职场文书
节能宣传周活动总结
2014/05/08 职场文书
含预算的公司户外活动方案
2014/08/16 职场文书
机关党员公开承诺书
2014/08/30 职场文书
《我爱祖国》演讲稿1000字
2014/09/26 职场文书
医院领导班子四风问题对照检查材料
2014/10/26 职场文书
2014年科协工作总结
2014/12/09 职场文书
婚礼双方父亲致辞
2015/07/27 职场文书
银行柜员优质服务心得体会
2016/01/22 职场文书