利用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 相关文章推荐
linux 下实现python多版本安装实践
Nov 18 Python
python实现的文件夹清理程序分享
Nov 22 Python
Python实现简单的四则运算计算器
Nov 02 Python
tensorflow学习笔记之mnist的卷积神经网络实例
Apr 15 Python
opencv python 基于KNN的手写体识别的实例
Aug 03 Python
python分批定量读取文件内容,输出到不同文件中的方法
Dec 08 Python
Python3网络爬虫中的requests高级用法详解
Jun 18 Python
Python全面分析系统的时域特性和频率域特性
Feb 26 Python
sklearn的predict_proba使用说明
Jun 28 Python
python中关于数据类型的学习笔记
Jul 19 Python
Python tkinter界面实现历史天气查询的示例代码
Aug 23 Python
python 使用paramiko模块进行封装,远程操作linux主机的示例代码
Dec 03 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 header函数分析详解
2011/08/06 PHP
PHP的简易冒泡法代码分享
2012/08/28 PHP
php实现的单一入口应用程序实例分析
2015/09/23 PHP
php解决安全问题的方法实例
2019/09/19 PHP
JavaScript 模拟用户单击事件
2009/12/31 Javascript
文本框回车提交与禁止提交示例
2013/09/27 Javascript
javascript中字符串的定义示例代码
2013/12/19 Javascript
Jquery.Form 异步提交表单的简单实例
2014/03/03 Javascript
AngularJs实现ng1.3+表单验证
2015/12/10 Javascript
jquery的checkbox,radio,select等方法小结
2016/08/30 Javascript
Vue.js绑定HTML class数组语法错误的原因分析
2016/10/19 Javascript
Bootstrap Search Suggest使用例子
2016/12/21 Javascript
Mui使用jquery并且使用点击跳转新窗口的实例
2017/08/19 jQuery
十个免费的web前端开发工具详细整理
2017/09/18 Javascript
vue.js实例对象+组件树的详细介绍
2017/10/20 Javascript
js+css实现打字效果
2020/06/24 Javascript
VUE DOM加载后执行自定义事件的方法
2018/09/07 Javascript
详解angularjs4部署文件过大解决过程
2018/12/05 Javascript
JavaScript字符串处理常见操作方法小结
2019/11/15 Javascript
Vue+Node服务器查询Mongo数据库及页面数据传递操作实例分析
2019/12/20 Javascript
Webpack3+React16代码分割的实现
2021/03/03 Javascript
python实现邮件自动发送
2019/08/10 Python
CSS3实现多背景展示效果通过CSS3定位多张背景
2014/08/10 HTML / CSS
adidas澳大利亚官方网站:adidas Australia
2018/04/15 全球购物
工程部主管岗位职责
2013/11/17 职场文书
专营店会计助理岗位职责
2013/11/29 职场文书
大学生自荐书范文
2013/12/10 职场文书
全国道德模范事迹
2014/02/01 职场文书
少先队入队活动方案
2014/02/08 职场文书
内蒙古鄂尔多斯市市长寄语
2014/04/10 职场文书
2014年秋季新学期寄语
2014/08/02 职场文书
户籍证明模板
2014/09/28 职场文书
学校证明范文
2015/06/24 职场文书
自愿离婚协议书范本2016
2016/03/18 职场文书
市直属机关2016年主题党日活动总结
2016/04/05 职场文书