利用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实现把utf-8格式的文件转换成gbk格式的文件
Jan 22 Python
Python基于pygame实现图片代替鼠标移动效果
Nov 11 Python
Python中协程用法代码详解
Feb 10 Python
python socket网络编程之粘包问题详解
Apr 28 Python
python实时监控cpu小工具
Jun 21 Python
详解python 注释、变量、类型
Aug 10 Python
python中join()方法介绍
Oct 11 Python
详解pandas的外部数据导入与常用方法
May 01 Python
tensorflow保持每次训练结果一致的简单实现
Feb 17 Python
keras 两种训练模型方式详解fit和fit_generator(节省内存)
Jul 03 Python
python MD5加密的示例
Oct 19 Python
使用Python制作一盏 3D 花灯喜迎元宵佳节
Feb 26 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天翼开放平台短信发送接口实现方法
2014/12/22 PHP
Laravel 5框架学习之表单验证
2015/04/08 PHP
js window.event对象详尽解析
2009/02/17 Javascript
JavaScript将数字转换成大写中文的方法
2015/03/23 Javascript
谈谈我对JavaScript DOM事件的理解
2015/12/18 Javascript
图文详解Heap Sort堆排序算法及JavaScript的代码实现
2016/05/04 Javascript
jQuery侧边栏实现代码
2016/05/06 Javascript
jQuery progressbar通过Ajax请求实现后台进度实时功能
2016/10/11 Javascript
bootstrap日历插件datetimepicker使用方法
2016/12/14 Javascript
ThinkPHP+jquery实现“加载更多”功能代码
2017/03/11 Javascript
jQuery实现菜单栏导航效果
2017/08/15 jQuery
前端把html表格生成为excel表格的实例
2017/09/19 Javascript
jquery animate动画持续运动的实例
2017/11/29 jQuery
bootstrap3中container与container_fluid外层容器的区别讲解
2017/12/04 Javascript
vue.js在标签属性中插入变量参数的方法
2018/03/06 Javascript
vue 实现通过手机发送短信验证码注册功能
2018/04/19 Javascript
Vue 莹石摄像头直播视频实例代码
2018/08/31 Javascript
如何使用 vue-cli 创建模板项目
2020/11/19 Vue.js
[05:43]VG.R战队教练Mikasa专访:为目标从未停止战斗
2016/08/02 DOTA
[01:59]深扒TI7聊天轮盘语音出处 1
2017/05/11 DOTA
python实现一次创建多级目录的方法
2015/05/15 Python
Python中http请求方法库汇总
2016/01/06 Python
浅谈python实现Google翻译PDF,解决换行的问题
2018/11/28 Python
在numpy矩阵中令小于0的元素改为0的实例
2019/01/26 Python
django 自定义过滤器(filter)处理较为复杂的变量方法
2019/08/12 Python
python将YUV420P文件转PNG图片格式的两种方法
2021/01/22 Python
服务之星获奖感言
2014/01/21 职场文书
《十六年前的回忆》教学反思
2014/02/14 职场文书
优秀实习生感言
2014/03/01 职场文书
2014年煤矿工人工作总结
2014/12/08 职场文书
物业接待员岗位职责
2015/04/15 职场文书
宇宙与人观后感
2015/06/05 职场文书
如何在向量化NumPy数组上进行移动窗口
2021/05/18 Python
MySQL系列之十二 备份与恢复
2021/07/02 MySQL
Flask response响应的具体使用
2021/07/15 Python
Anaconda安装pytorch和paddle的方法步骤
2022/04/03 Python