日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

Python裝飾器實(shí)現(xiàn)幾類驗(yàn)證功能做法實(shí)例

系統(tǒng) 1692 0

最近新需求來了,要給系統(tǒng)增加幾個(gè)資源權(quán)限。盡量減少代碼的改動(dòng)和程序的復(fù)雜程度。所以還是使用裝飾器比較科學(xué)

之前用了一些登錄驗(yàn)證的現(xiàn)成裝飾器模塊。然后仿寫一些用戶管理部分的權(quán)限裝飾器。

比如下面這種

            
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)

          

調(diào)用權(quán)限的時(shí)候很好理解。直接仿寫admin_required的格式就好了。然后每個(gè)頁面入口用語法糖這樣寫: @admin_required

于是頁面的入口權(quán)限就做好了。但是資源權(quán)限和頁面權(quán)限不同。上面內(nèi)容中提到的permission是寫在model.py的靜態(tài)內(nèi)容里面的。

從封裝來看,至少是看不出來哪個(gè)地方暴露了用戶查詢的方法(菜鳥水平下)。只能簡(jiǎn)單的看出來if判斷的時(shí)候似乎使用了current_user這個(gè)變量的內(nèi)置方法

但是current_user其實(shí)是一個(gè)第三方的包的內(nèi)容,和登錄模塊引入的包相同,是一整套記錄token信息的代碼。詳細(xì)內(nèi)容太多。從這個(gè)地方出發(fā)去寫,會(huì)go die

因?yàn)槟呐挛抑榔鋵?shí)調(diào)用的.can(permission)是model類里面定義的類方法。可是current_user是取了哪個(gè)部分的東西還是不清楚。

所以不管它。從頭來梳理一下裝飾器的內(nèi)容。

首先一個(gè)簡(jiǎn)單的裝飾器寫法是很好理解的。比如原函數(shù)是這樣寫的:

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

這當(dāng)然是隨便寫的一個(gè)函數(shù)(明顯有很多問題),只是用來表達(dá)一個(gè)過程。首先通過路由調(diào)用這個(gè)函數(shù)的時(shí)候,會(huì)先執(zhí)行第一個(gè)if判斷。這個(gè)判斷即我們想要的驗(yàn)證內(nèi)容

驗(yàn)證通過以后,說明用戶可以訪問這個(gè)頁面,然后頁面內(nèi)容會(huì)渲染出來,交互功能也被允許……

那么裝飾器,就是把這個(gè)if的功能提取出來了。那么原函數(shù)寫成這樣的形式:

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

    if request.method=='POST':

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

          

單從這個(gè)函數(shù)來說,這樣寫并沒有任何好處,似乎本來一行代碼搞定的問題,多用了幾行代碼。我們展開這個(gè)形式的完整代碼看一下:

            
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這一句寫成了@模式。

但是這種寫法只能解決最基本的驗(yàn)證問題。也就是相對(duì)獨(dú)立的入口驗(yàn)證。這個(gè)驗(yàn)證還沒有拿到程序傳遞到page()函數(shù)當(dāng)中的參數(shù)。也就是說,這個(gè)驗(yàn)證這么看起來沒什么用處

不過機(jī)制是這樣。接下來就可以研究怎樣的做法是把路由傳遞過來的請(qǐng)求數(shù)據(jù)進(jìn)行驗(yàn)證然后繼續(xù)執(zhí)行的了。

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

同樣的,多個(gè)參數(shù)的時(shí)候,只需要把 def inner(arg)改寫成def inner(arg1,arg2)

n個(gè)參數(shù)的時(shí)候,則寫成def inner(*args,**kwargs) 這個(gè)需要注意一下。*args是元組,即('user',1);**kwargs是字典,即{'user':1}

同時(shí)寫這兩個(gè)形參的話,基本上就能處理所有傳遞進(jìn)來的參數(shù)類型了。

當(dāng)然。除此以外還有更復(fù)雜的裝飾器寫法。不過能處理傳遞過來的參數(shù)并且不影響被裝飾函數(shù)的正常執(zhí)行。基本上實(shí)現(xiàn)了之前的功能。

那么回過頭來看示例當(dāng)中的寫法。最外層使用def permission_required(permission): 的意義,顯然是想要實(shí)現(xiàn)復(fù)用。

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

上面的(permission)形參顯然對(duì)應(yīng)permission_required(Permission.SMY)中(Permission.SMY)這個(gè)參數(shù)。把這個(gè)參數(shù)的形參傳遞到方法體內(nèi)部

這也是為什么要在裝飾器decorator(f)外面再嵌套一層函數(shù)的原因――實(shí)現(xiàn)復(fù)用

于是之前這個(gè)寫法的內(nèi)容就很清晰了

            
def permission_required(permission):

#通過形參實(shí)現(xiàn)了一個(gè)裝飾器類。對(duì)于不同針對(duì)性的裝飾器,都可以調(diào)用這個(gè)函數(shù)的實(shí)現(xiàn),而只需要做最小的改動(dòng)(傳遞形參)
  def decorator(f):
  #這個(gè)才是裝飾器開始執(zhí)行的第一步
    @wraps(f)
    #這個(gè)裝飾器實(shí)際上是為了保證函數(shù)的原始屬性不發(fā)生改變。所謂原始屬性,指的是__name__ 這種屬性
    def decorated_function(*args, **kwargs):
    #這個(gè)裝飾器方法把原函數(shù)的形參繼承了。因此實(shí)際上相當(dāng)于在原函數(shù)開頭增加了這個(gè)函數(shù)的內(nèi)容
      if not current_user.can(permission):
      #這個(gè)地方很明顯。current_user是從內(nèi)存中取(服務(wù)端),然后permission就會(huì)根據(jù)我們實(shí)際需要驗(yàn)證的permission進(jìn)行形參到實(shí)參的轉(zhuǎn)化
        abort(403)
        #明顯的異常處理,當(dāng)然,403是一個(gè)粗暴的方法。更粗暴的方法,我會(huì)用redirect(url_for(logout))...
      return f(*args, **kwargs)
      #結(jié)束判斷,把參數(shù)傳遞給原函數(shù)(此處的f()即是原函數(shù)(更具體的權(quán)限驗(yàn)證裝飾器),只是f是個(gè)丑陋的形參而已)
    return decorated_function
  return decorator


          

這樣差不多就結(jié)束了。如果有人想補(bǔ)充,歡迎留言。

以上這篇Python裝飾器實(shí)現(xiàn)幾類驗(yàn)證功能做法實(shí)例就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 资源县| 胶南市| 金湖县| 化隆| 灵寿县| 奉化市| 鄢陵县| 颍上县| 手游| 博湖县| 南漳县| 盘山县| 德江县| 邓州市| 息烽县| 仙游县| 忻城县| 绥滨县| 宜宾市| 准格尔旗| 自治县| 巴楚县| 涡阳县| 泰顺县| 全州县| 成都市| 新晃| 汉沽区| 蒙阴县| 罗源县| 塔河县| 阜平县| 界首市| 宣武区| 卓尼县| 海口市| 康平县| 麻阳| 兰溪市| 大方县| 呼和浩特市|