利用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 内置字符串处理函数的使用方法
Jun 11 Python
Python中用函数作为返回值和实现闭包的教程
Apr 27 Python
Python的Flask框架中使用Flask-Migrate扩展迁移数据库的教程
Jun 14 Python
Python3学习urllib的使用方法示例
Nov 29 Python
浅谈机器学习需要的了解的十大算法
Dec 15 Python
详解Python3 中hasattr()、getattr()、setattr()、delattr()函数及示例代码数
Apr 18 Python
详解pandas删除缺失数据(pd.dropna()方法)
Jun 25 Python
python如何基于redis实现ip代理池
Jan 17 Python
Python 私有属性和私有方法应用场景分析
Jun 19 Python
python 实现压缩和解压缩的示例
Sep 22 Python
python字符串拼接+和join的区别详解
Dec 03 Python
Python IO文件管理的具体使用
Mar 20 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
暴雪前总裁遗憾:没尽早追赶Dota 取消星际争霸幽灵
2020/03/08 星际争霸
基于PHP实现用户在线状态检测
2020/11/10 PHP
jQuery下通过replace字符串替换实现大小图片切换
2012/05/22 Javascript
解析dom中的children对象数组元素firstChild,lastChild的使用
2013/07/10 Javascript
javascript使用百度地图api和html5特性获取浏览器位置
2014/01/10 Javascript
非jQuery实现照片散落桌子上,单击放大的LightBox效果
2014/11/28 Javascript
JQuery radio(单选按钮)操作方法汇总
2015/04/15 Javascript
js实现完美兼容各大浏览器的人民币大小写相互转换
2015/10/29 Javascript
javascript定义类和类的实现实例详解
2015/12/01 Javascript
由浅入深讲解Javascript继承机制与simple-inheritance源码分析
2015/12/13 Javascript
利用JS生成博文目录及CSS定制博客
2016/02/10 Javascript
jQuery实现鼠标滚动图片延迟加载效果附源码下载
2016/06/28 Javascript
JS原型与原型链的深入理解
2017/02/15 Javascript
在vue中使用css modules替代scroped的方法
2018/03/10 Javascript
Vue常用指令详解分析
2018/08/19 Javascript
详解JS取出两个数组中的不同或相同元素
2019/03/20 Javascript
微信小程序 自定义弹窗实现过程(附代码)
2019/12/05 Javascript
Vue父子组件传值的一些坑
2020/09/16 Javascript
Python之日期与时间处理模块(date和datetime)
2017/02/16 Python
python提取图像的名字*.jpg到txt文本的方法
2018/05/10 Python
win10下tensorflow和matplotlib安装教程
2018/09/19 Python
Django中celery执行任务结果的保存方法
2019/07/12 Python
Python 多线程共享变量的实现示例
2020/04/17 Python
使用Python pip怎么升级pip
2020/08/11 Python
Django创建一个后台的基本步骤记录
2020/10/02 Python
python的scipy.stats模块中正态分布常用函数总结
2021/02/19 Python
使用phonegap克隆和删除联系人的实现方法
2017/03/31 HTML / CSS
Omio意大利:全欧洲低价大巴、火车和航班搜索和比价
2017/12/02 全球购物
大学本科生的个人自我评价
2013/12/09 职场文书
社区工作者思想汇报
2014/01/13 职场文书
搞笑获奖感言
2014/01/30 职场文书
《尊严》教学反思
2014/02/11 职场文书
应届毕业生自荐信
2014/05/28 职场文书
教师年终个人总结
2015/02/11 职场文书
工作年限证明模板
2015/06/15 职场文书
Android Studio实现带三角函数对数运算功能的高级计算器
2022/05/20 Java/Android