利用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实现的生成随机迷宫算法核心代码分享(含游戏完整代码)
Jul 11 Python
使用Python发送邮件附件以定时备份MySQL的教程
Apr 25 Python
利用Celery实现Django博客PV统计功能详解
May 08 Python
Python优先队列实现方法示例
Sep 21 Python
使用Python从零开始撸一个区块链
Mar 14 Python
利用Python批量提取Win10锁屏壁纸实战教程
Mar 27 Python
python随机取list中的元素方法
Apr 08 Python
对python PLT中的image和skimage处理图片方法详解
Jan 10 Python
python3实现将json对象存入Redis以及数据的导入导出
Jul 16 Python
python学习笔记之多进程
Aug 06 Python
Pytorch 图像变换函数集合小结
Feb 01 Python
利用Pycharm连接服务器的全过程记录
Jul 01 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
PHP 小心urldecode引发的SQL注入漏洞
2011/10/27 PHP
解析用PHP实现var_export的详细介绍
2013/06/20 PHP
Yii Framework框架获取分类下面的所有子类方法
2014/06/20 PHP
JavaScript 实现模态对话框 源代码大全
2009/05/02 Javascript
SharePoint 客户端对象模型 (一) ECMA Script
2011/05/22 Javascript
JavaScript打印iframe内容示例代码
2013/08/20 Javascript
js关于字符长度限制的问题示例探讨
2014/01/24 Javascript
js通过iframe加载外部网页的实现代码
2015/04/05 Javascript
基于JavaScript怎么实现让歌词滚动播放
2015/11/03 Javascript
js控制TR的显示隐藏
2016/03/04 Javascript
完美实现八种js焦点轮播图(下篇)
2020/04/20 Javascript
JavaScript提高网站性能优化的建议(二)
2016/07/24 Javascript
jquery-mobile表单的创建方法详解
2016/11/23 Javascript
javascript读取文本节点方法小结
2016/12/15 Javascript
ES6新数据结构Set与WeakSet用法分析
2017/03/31 Javascript
vue使用stompjs实现mqtt消息推送通知
2017/06/22 Javascript
Angular 4.X开发实践中的踩坑小结
2017/07/04 Javascript
JS实现unicode和UTF-8之间的互相转换互转
2017/07/05 Javascript
node使用UEditor富文本编辑器的方法实例
2017/07/11 Javascript
Vue项目webpack打包部署到Tomcat刷新报404错误问题的解决方案
2018/05/15 Javascript
浅谈针对Vue相同路由不同参数的刷新问题
2018/09/29 Javascript
layui递归实现动态左侧菜单
2019/07/26 Javascript
angularjs自定义过滤器demo示例
2019/08/24 Javascript
Vue+penlayers实现多边形绘制及展示
2020/12/24 Vue.js
Python中比较特别的除法运算和幂运算介绍
2015/04/05 Python
使用Python操作MySQL的一些基本方法
2015/08/16 Python
Python 基础教程之包和类的用法
2017/02/23 Python
对Python3中的print函数以及与python2的对比分析
2018/05/02 Python
python numpy 显示图像阵列的实例
2018/07/02 Python
法学个人求职信范文
2014/01/27 职场文书
会务接待方案
2014/02/27 职场文书
公司年终奖分配方案
2014/06/16 职场文书
一年级语文下册复习计划
2015/01/17 职场文书
酒店销售经理岗位职责
2015/04/02 职场文书
php微信小程序解包过程实例详解
2021/03/31 PHP