Python装饰器实现几类验证功能做法实例

转载  更新时间:2017年05月18日 08:28:44   投稿:jingxian   我要评论

下面小编就为大家带来一篇Python装饰器实现几类验证功能做法实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

最近新需求来了,要给系统增加几个资源权限。尽量减少代码的改动和程序的复杂程度。所以还是使用装饰器比较科学

之前用了一些登录验证的现成装饰器模块。然后仿写一些用户管理部分的权限装饰器。

比如下面这种

def permission_required(permission):
  def decorator(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
      if not current_user.can(permission):
        abort(403)
      return f(*args, **kwargs)
    return decorated_function
  return decorator

def admin_required(f):
  return permission_required(Permission.SMY)(f)

调用权限的时候很好理解。直接仿写admin_required的格式就好了。然后每个页面入口用语法糖这样写: @admin_required

于是页面的入口权限就做好了。但是资源权限和页面权限不同。上面内容中提到的permission是写在model.py的静态内容里面的。

从封装来看,至少是看不出来哪个地方暴露了用户查询的方法(菜鸟水平下)。只能简单的看出来if判断的时候似乎使用了current_user这个变量的内置方法

但是current_user其实是一个第三方的包的内容,和登录模块引入的包相同,是一整套记录token信息的代码。详细内容太多。从这个地方出发去写,会go die

因为哪怕我知道其实调用的.can(permission)是model类里面定义的类方法。可是current_user是取了哪个部分的东西还是不清楚。

所以不管它。从头来梳理一下装饰器的内容。

首先一个简单的装饰器写法是很好理解的。比如原函数是这样写的:

def page():
  if user == 'admin':
    form = Form()
    
    if request.method=='POST':
      
      db.session.add(form)
      db.session.commit()
      flash("success")
      return 0

这当然是随便写的一个函数(明显有很多问题),只是用来表达一个过程。首先通过路由调用这个函数的时候,会先执行第一个if判断。这个判断即我们想要的验证内容

验证通过以后,说明用户可以访问这个页面,然后页面内容会渲染出来,交互功能也被允许……

那么装饰器,就是把这个if的功能提取出来了。那么原函数写成这样的形式:

@admin_check
def page():
    form = Form()

    if request.method=='POST':

      db.session.add(form)
      db.session.commit()
      flash("success")
      return 0

单从这个函数来说,这样写并没有任何好处,似乎本来一行代码搞定的问题,多用了几行代码。我们展开这个形式的完整代码看一下:

def admincheck(func):
  if user=='admin':
    return func
  
def page():
    form = Form()

    if request.method=='POST':

      db.session.add(form)
      db.session.commit()
      flash("success")
      return 0

page = admincheck(page())

上面的装饰器只是把page=admincheck这一句写成了@模式。

但是这种写法只能解决最基本的验证问题。也就是相对独立的入口验证。这个验证还没有拿到程序传递到page()函数当中的参数。也就是说,这个验证这么看起来没什么用处

不过机制是这样。接下来就可以研究怎样的做法是把路由传递过来的请求数据进行验证然后继续执行的了。

def admincheck(func):
  def inner(arg):
    if user == 'admin':
      if arg == 'false':
        abort(403)
    return func(arg)
  return inner

同样的,多个参数的时候,只需要把 def inner(arg)改写成def inner(arg1,arg2)

n个参数的时候,则写成def inner(*args,**kwargs) 这个需要注意一下。*args是元组,即('user',1);**kwargs是字典,即{'user':1}

同时写这两个形参的话,基本上就能处理所有传递进来的参数类型了。

当然。除此以外还有更复杂的装饰器写法。不过能处理传递过来的参数并且不影响被装饰函数的正常执行。基本上实现了之前的功能。

那么回过头来看示例当中的写法。最外层使用def permission_required(permission): 的意义,显然是想要实现复用。

def admin_required(f):
  return permission_required(Permission.SMY)(f)

上面的(permission)形参显然对应permission_required(Permission.SMY)中(Permission.SMY)这个参数。把这个参数的形参传递到方法体内部

这也是为什么要在装饰器decorator(f)外面再嵌套一层函数的原因——实现复用

于是之前这个写法的内容就很清晰了

def permission_required(permission):

#通过形参实现了一个装饰器类。对于不同针对性的装饰器,都可以调用这个函数的实现,而只需要做最小的改动(传递形参)
  def decorator(f):
  #这个才是装饰器开始执行的第一步
    @wraps(f)
    #这个装饰器实际上是为了保证函数的原始属性不发生改变。所谓原始属性,指的是__name__ 这种属性
    def decorated_function(*args, **kwargs):
    #这个装饰器方法把原函数的形参继承了。因此实际上相当于在原函数开头增加了这个函数的内容
      if not current_user.can(permission):
      #这个地方很明显。current_user是从内存中取(服务端),然后permission就会根据我们实际需要验证的permission进行形参到实参的转化
        abort(403)
        #明显的异常处理,当然,403是一个粗暴的方法。更粗暴的方法,我会用redirect(url_for(logout))...
      return f(*args, **kwargs)
      #结束判断,把参数传递给原函数(此处的f()即是原函数(更具体的权限验证装饰器),只是f是个丑陋的形参而已)
    return decorated_function
  return decorator

这样差不多就结束了。如果有人想补充,欢迎留言。

以上这篇Python装饰器实现几类验证功能做法实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • CentOS 7下安装Python 3.5并与Python2.7兼容并存详解

    CentOS 7下安装Python 3.5并与Python2.7兼容并存详解

    这篇文章主要给大家介绍了在CentOS 7下安装Python 3.5并与Python2.7兼容并存的相关资料,文中将安装步骤介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
    2017-07-07
  • 详解Python中的日志模块logging

    详解Python中的日志模块logging

    这篇文章主要介绍了Python中的日志模块logging,包括Python下的日志级别以及模块内常用方法的使用,需要的朋友可以参考下
    2015-06-06
  • Python中实现对list做减法操作介绍

    Python中实现对list做减法操作介绍

    这篇文章主要介绍了Python中实现对list做减法操作介绍,需要的朋友可以参考下
    2015-01-01
  • 使用python实现个性化词云的方法

    使用python实现个性化词云的方法

    最近看到可视化的词云,看到网上也很多这样的工具,但是都不怎么完美,有些不支持中文,有的中文词频统计得莫名其妙、有的不支持自定义形状、所有的都不能自定义颜色,于是网上找了一下,决定用python绘制词云
    2017-06-06
  • json跨域调用python的方法详解

    json跨域调用python的方法详解

    这篇文章主要介绍了json跨域调用python的方法,结合实例形式分析了基于ajax的json调用及Python后台处理技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2017-01-01
  • Python操作SQLite数据库的方法详解

    Python操作SQLite数据库的方法详解

    这篇文章主要介绍了Python操作SQLite数据库的方法,较为详细的分析了Python安装sqlite数据库模块及针对sqlite数据库的常用操作技巧,需要的朋友可以参考下
    2017-06-06
  • Python itertools模块详解

    Python itertools模块详解

    这篇文章主要介绍了Python itertools模块详解,本文基本是基于文档的翻译和补充,相当于翻译了,需要的朋友可以参考下
    2015-05-05
  • 浅谈python jieba分词模块的基本用法

    浅谈python jieba分词模块的基本用法

    本篇文章主要介绍了浅谈python jieba分词模块的基本用法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • python根据京东商品url获取产品价格

    python根据京东商品url获取产品价格

    闲着没事尝试抓一下京东的数据,需要使用到的库有:BeautifulSoup,urllib2,在Python2下测试通过
    2015-08-08
  • Python入门_浅谈逻辑判断与运算符

    Python入门_浅谈逻辑判断与运算符

    下面小编就为大家带来一篇Python入门_浅谈逻辑判断与运算符。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05

最新评论