Flask token配置與 用戶分組(三)

Token的配置

生成Token: TimedJSONWebSignatureSerializer進行序列化

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

from flask import current_app, jsonify
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

from app.libs.enums import ClientTypeEnum
from app.libs.redprint import RedPrint
from app.models.user import User
from app.validators.forms import ClientForm

api = RedPrint('token')


@api.route('', methods=['POST'])
def get_token():
    form = ClientForm().validate_for_api()
    promise = {
        ClientTypeEnum.USER_EMAIL: User.verify
    }
    identify = promise[ClientTypeEnum(form.type.data)](
        form.account.data,
        form.secret.data
    )
    # 生成令牌
    expiration = current_app.config['TOKEN_EXPIRATION']
    token = generate_auth_token(identify['uid'],
                                form.type.data,
                                identify['scope'],
                                expiration)

    # 注意需要進行 ascii 編碼
    t = {
        'token': token.decode('ascii')
    }
    return jsonify(t, 201)


def generate_auth_token(uid, ac_type, scope=None, expiration=7200):
    """
    生成token议谷,將用戶的id,作用域鞠眉,用戶類型猾封,過期時間寫入token
    :param uid: 用戶id
    :param ac_type: 用戶類型
    :param scope: 權(quán)限域
    :param expiration: 過期時間 秒
    :return:
    """
    s = Serializer(current_app.config['SECRET_KEY'],
                   expires_in=expiration,
                   )
    return s.dumps({'uid': uid,
                    'type': ac_type.value,
                    'scope': scope
                    })

Token的驗證,在用戶調(diào)取接口等相關(guān)的操作的時候奢米,對token進行驗證的操作淹真,傳遞token是在http的請求頭中 Authorization 字段中

#使用示例讶迁,注意必須放到放到方法名上
@api.route('', methods=['GET'])
@auth.login_required
def get_user():
    uid = g.user.uid
    user = User.query.filter_by(id=uid).first_or_404()
    return jsonify(user)


#驗證相關(guān)代碼
from collections import namedtuple
from flask import current_app, g, request
from flask_httpauth import HTTPBasicAuth
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, BadSignature, SignatureExpired
from app.libs.error_code import AuthFailed, Forbidden
from app.libs.scope import is_in_scope

auth = HTTPBasicAuth()
#使用nametuple生成類
User = namedtuple('User', ['uid', 'ac_type', 'scope'])

@auth.verify_password
def verify_password(token, password):
    # http的協(xié)議規(guī)范
    # key = Authorization
    # value = basic base64(rjl:111111)
    user_info = verify_auth_token(token)
    if not user_info:
        return False
    else:
        g.user = user_info
        return True

# 驗證不通過,直接返回相關(guān)的信息,從token中獲取用戶相關(guān)的信息
def verify_auth_token(token):
    s = Serializer(current_app.config['SECRET_KEY'])
    try:
        data = s.loads(token)
    except BadSignature:
        raise AuthFailed(msg='token is invalid', error_code=1002)
    except SignatureExpired:
        raise AuthFailed(msg='token is expired', error_code=1003)
    uid = data['uid']
    ac_type = data['type']
    scope = data['scope']
    # request 視圖函數(shù)
    allow = is_in_scope(scope, request.endpoint)
    if not allow:
        raise Forbidden()
    return User(uid, ac_type, scope)

用戶對接口操作權(quán)限的判斷

在用戶登錄操作的時候把用戶的等級標志寫入token中核蘸,根據(jù)token的信息巍糯,與當前用戶的等級進行判斷!

將相應(yīng)用戶可以訪問的視圖函數(shù),存儲起來客扎,當用戶請求的時候祟峦,查看是> 否在該作用域中。

定義作于域:

class Scope:
    # 視圖函數(shù)級別的區(qū)分
    allow_api = []

    # 模塊級別的定義區(qū)分
    allow_module = []

    # 排除
    forbidden_api = []

    def __add__(self, other):
        self.allow_api = self.allow_api + other.allow_api
        # set去重徙鱼,再轉(zhuǎn)為list
        self.allow_api = list(set(self.allow_api))

        self.allow_module = self.allow_module + other.allow_module
        self.allow_module = list(set(self.allow_module))

        return self

#定義管理權(quán)限組
class AdminScope(Scope):
    allow_module = [
        'v1.user'
    ]
    # def __init__(self):
    #     self + UserScope()

#普通用戶組
class UserScope(Scope):
    allow_api = [
        'v1.user+get_user'
    ]

    def __init__(self):
        pass

#超級管理員組
class SuperScope(Scope):
    """
    超級管理員宅楞,權(quán)限相加
    """
    allow_api = [

    ]
    allow_module = [
        'v1.user'
    ]
    def __init__(self):
        self + AdminScope() + UserScope()


#驗證權(quán)限
def is_in_scope(scope, endpoint):
    """
    根據(jù)視圖函數(shù)名判斷,該視圖函數(shù)是否在 權(quán)限組中
    :param scope:
    :param endpoint:
    :return:
    """
    # 反射 ,注意endpoint的路徑是帶有 blueprint的路徑的
    scope = globals()[scope]()
    # 查看定義 redprint的 位置
    splits = endpoint.split('+')
    red_name = splits[0]
    if endpoint in scope.forbidden_api:
        return False
    if endpoint in scope.allow_api:
        return True
    if red_name in scope.allow_module:
        return True
    else:
        return False

與token的數(shù)據(jù)進行校驗

. . .
uid = data['uid']
ac_type = data['type']
scope = data['scope']
# request 視圖函數(shù)
allow = is_in_scope(scope, request.endpoint)
if not allow:
    raise Forbidden()
. . .

tips:模塊級別的校驗袱吆,需要更改 redprint的 endpoint

class RedPrint:
def __init__(self, name):
    self.name = name
    self.mound = []

def route(self, rule, **options):
    def decorator(f):
        self.mound.append((f, rule, options))
        return f

    return decorator

def register(self, bp, url_prefix=None):
    """
    將 redprint注冊到 blueprint厌衙,實際調(diào)用 blueprint代碼
    """
    if url_prefix is None:
        url_prefix = '/' + self.name
    for f, rule, options in self.mound:
        # 自定義 endpoint
        endpoint = self.name + '+' + options.pop("endpoint", f.__name__)
        bp.add_url_rule(url_prefix + rule, endpoint, f, **options)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市绞绒,隨后出現(xiàn)的幾起案子婶希,更是在濱河造成了極大的恐慌,老刑警劉巖蓬衡,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喻杈,死亡現(xiàn)場離奇詭異拐揭,居然都是意外死亡,警方通過查閱死者的電腦和手機奕塑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來家肯,“玉大人龄砰,你說我怎么就攤上這事√忠拢” “怎么了换棚?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長反镇。 經(jīng)常有香客問我固蚤,道長,這世上最難降的妖魔是什么歹茶? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任夕玩,我火速辦了婚禮,結(jié)果婚禮上惊豺,老公的妹妹穿的比我還像新娘燎孟。我一直安慰自己,他們只是感情好尸昧,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布揩页。 她就那樣靜靜地躺著,像睡著了一般烹俗。 火紅的嫁衣襯著肌膚如雪爆侣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天幢妄,我揣著相機與錄音兔仰,去河邊找鬼。 笑死磁浇,一個胖子當著我的面吹牛斋陪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播置吓,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼无虚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了衍锚?” 一聲冷哼從身側(cè)響起友题,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎戴质,沒想到半個月后度宦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踢匣,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年戈抄,在試婚紗的時候發(fā)現(xiàn)自己被綠了离唬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡划鸽,死狀恐怖输莺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情裸诽,我是刑警寧澤嫂用,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站丈冬,受9級特大地震影響嘱函,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜埂蕊,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一往弓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧粒梦,春花似錦亮航、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至泄朴,卻和暖如春重抖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背祖灰。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工钟沛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人局扶。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓恨统,卻偏偏與公主長得像,于是被迫代替她去往敵國和親三妈。 傳聞我的和親對象是個殘疾皇子畜埋,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 國家電網(wǎng)公司企業(yè)標準(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,869評論 6 13
  • 22年12月更新:個人網(wǎng)站關(guān)停,如果仍舊對舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,160評論 22 257
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理畴蒲,服務(wù)發(fā)現(xiàn)悠鞍,斷路器,智...
    卡卡羅2017閱讀 134,601評論 18 139
  • 日子一天一天過模燥,看著2018年過了六分之一的時候咖祭,感覺一陣恐慌掩宜,什么事情都還沒有做,時間流逝太快么翰,再不明確和改變牺汤,...
    王少軍_6de4閱讀 100評論 0 1
  • 2018年6月 8日 周五 晴 我身體不舒服了兩天,兒子就像變了一個小大人浩嫌,今天上學(xué)要求他爸...
    張志成娘閱讀 326評論 0 4