利用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连接oracle数据库实例
Oct 17 Python
python求列表交集的方法汇总
Nov 10 Python
python通过BF算法实现关键词匹配的方法
Mar 13 Python
简单谈谈Python流程控制语句
Dec 04 Python
python MySQLdb使用教程详解
Mar 20 Python
新年快乐! python实现绚烂的烟花绽放效果
Jan 30 Python
Python2.7版os.path.isdir中文路径返回false的解决方法
Jun 21 Python
将python运行结果保存至本地文件中的示例讲解
Jul 11 Python
python字符串切割:str.split()与re.split()的对比分析
Jul 16 Python
Django为窗体加上防机器人的验证码功能过程解析
Aug 14 Python
python中文分词库jieba使用方法详解
Feb 11 Python
Python如何telnet到网络设备
Feb 18 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仿ZOL分页类代码
2008/10/02 PHP
IIS下PHP的三种配置方式对比
2014/11/20 PHP
初识通用数据库操作类――前端easyui-datagrid,form(php)
2015/07/31 PHP
php实现的简单数据库操作Model类
2016/11/16 PHP
php+ajax实现无刷新文件上传功能(ajaxuploadfile)
2018/02/11 PHP
为Plesk PHP7启用Oracle OCI8扩展方法总结
2019/03/29 PHP
php设计模式之组合模式实例详解【星际争霸游戏案例】
2020/03/27 PHP
Extjs学习笔记之五 一个小细节renderTo和applyTo的区别
2010/01/07 Javascript
游览器中javascript的执行过程(图文)
2012/05/20 Javascript
JS判断当前日期是否大于某个日期的实现代码
2012/09/02 Javascript
jQuery Deferred和Promise创建响应式应用程序详细介绍
2013/03/05 Javascript
javascript实现获取cookie过期时间的变通方法
2014/08/14 Javascript
5个书写JavaScript代码的坏习惯,看看你中枪了没?
2014/11/06 Javascript
认识Knockout及如何使用Knockout绑定上下文
2015/12/25 Javascript
jquery+css实现侧边导航栏效果
2017/06/12 jQuery
让微信小程序支持ES6中Promise特性的方法详解
2017/06/13 Javascript
基于BootStrap实现简洁注册界面
2017/07/20 Javascript
jQuery实现简单聊天室
2020/02/08 jQuery
如何通过vscode运行调试javascript代码
2020/07/24 Javascript
[49:21]TNC vs VG 2019DOTA2国际邀请赛淘汰赛 胜者组赛BO3 第三场 8.20.mp4
2019/08/22 DOTA
使用Python求解最大公约数的实现方法
2015/08/20 Python
python 去除二维数组/二维列表中的重复行方法
2019/01/23 Python
python实现图片转字符小工具
2019/04/30 Python
Django之使用celery和NGINX生成静态页面实现性能优化
2019/10/08 Python
python matplotlib如何给图中的点加标签
2019/11/14 Python
Python如何获取文件指定行的内容
2020/05/27 Python
使用Tensorflow-GPU禁用GPU设置(CPU与GPU速度对比)
2020/06/30 Python
python 多线程死锁问题的解决方案
2020/08/25 Python
python matlab库简单用法讲解
2020/12/31 Python
工作失职检讨书范文
2014/01/16 职场文书
经济类毕业生求职信
2014/06/26 职场文书
优秀家长自荐材料
2014/08/26 职场文书
运动会跳远广播稿5篇
2014/09/17 职场文书
2015教师年度考核评语
2015/03/25 职场文书
小马王观后感
2015/06/11 职场文书
MySQL 存储过程的优缺点分析
2021/05/20 MySQL