Flask構(gòu)建SaaS應(yīng)用

租戶隔離

一個(gè)客戶就是一個(gè)租戶爷肝,每個(gè)租戶的數(shù)據(jù)在數(shù)據(jù)表中都有個(gè)一個(gè)tenantid字段用來(lái)與其他租戶隔離

  • 租戶識(shí)別
from flask import g, request
    
def get_tenant_from_request():
    auth = validate_auth(request.headers.get('Authorization'))
    return Tenant.query.get(auth.tenant_id)
        
def get_current_tenant():
    rv = getattr(g, 'current_tenant', None)
    if rv is = None:
        rv = get_tenant_from_request()
        g.current_tenant = rv
    return rv
  • 自動(dòng)租戶隔離

例如慷嗜,每個(gè)租戶有自己的Project筐骇,像下面這樣批量直接修改project又忘記帶上tenantid查詢字段录淡,就會(huì)把其他租戶的project一并修改了

def batch_update_projects(ids, changes):
    projects = Project.query.filter(
        Project.id.in_(ids) &
        Project.status != ProjectStatus.INVISIBLE
    )
    for project in projects: 
        update_projects(project, changes)

我們可以override Project的query屬性以及使用sqlalchemy的event listener來(lái)自動(dòng)的進(jìn)行租戶隔離,也就是說(shuō)我們?cè)谑褂胦rm查詢的時(shí)候亏娜,會(huì)自動(dòng)帶上tenentid查詢字段厦章,這樣無(wú)論是修改、刪除照藻、查詢都只會(huì)是操作自己租戶下面的數(shù)據(jù),畢竟在orm中汗侵,刪除和修改都是要先查詢的嘛

# model
class Project(TenantBoundMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))
    status = db.Column(db.Integer)
    def __repr__(self):
        return '<Project name=%r>' % self.name
from sqlalchemy.ext.declarative import declared_attr
?
# 覆寫(xiě)Project類的query_class屬性
class TenantQuery(db.Query):
    current_tenant_constrained = True
    def tenant_unconstrained_unsafe(self):
        rv = self._clone()
        rv.current_tenant_constrained = False
        return rv
# 通過(guò)mixin的方式幸缕,讓Project類多繼承這個(gè)類
# 從而覆寫(xiě)了Project類的query_class屬性
class TenantBoundMixin(object):
    query_class = TenantQuery
    # 為project表定義了一個(gè)tenant_id字段
    @declared_attr
    def tenant_id(cls):
        return db.Column(db.Integer, db.ForeignKey('tenant.id'))
?
    @declared_attr
    def tenant(cls):
        return db.relationship(Tenant, uselist=False)
?
# event_listener的意思是,每次執(zhí)行例如Project.query的時(shí)候都會(huì)執(zhí)行
# 下面的鉤子函數(shù)晰韵,
# 這個(gè)鉤子函數(shù)會(huì)給query對(duì)象帶上ilter_by(tenant=get_current_tenant())
@db.event.listens_for(TenantQuery, 'before_compile', retval=True)
def ensure_tenant_constrained(query):
    for desc in query.column_descriptions:
        if hasattr(desc['type'], 'tenant') and \
            query.current_tenant_constrained:
              query = query.filter_by(tenant=get_current_tenant())
    return query

接下來(lái)我們來(lái)看一下使用

# 只查詢我這個(gè)租戶名下的project42
>>> Project.query.all()
[<Project name='project42'>]
# 去掉租戶約束发乔,查詢所有project信息
>>> Project.query.tenant_unconstrained_unsafe().all()
[<Project name='project1'>, Project.name='project2', ...]

審計(jì)日志

def log(action, message=None):
  data = {
        'action': action
        'timestamp': datetime.utcnow()
  }
  if message is not None:
         data['message'] = message
  if request:
         data['ip'] = request.remote_addr
  user = get_current_user()
  if user is not None:
         data['user'] = User
  db.session.add(LogMessage(**data))

更多詳細(xì)信息,請(qǐng)參考

flask多租戶實(shí)踐

本篇文章由一文多發(fā)平臺(tái)ArtiPub自動(dòng)發(fā)布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雪猪,一起剝皮案震驚了整個(gè)濱河市栏尚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌只恨,老刑警劉巖译仗,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抬虽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡纵菌,警方通過(guò)查閱死者的電腦和手機(jī)阐污,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)咱圆,“玉大人笛辟,你說(shuō)我怎么就攤上這事⌒蛩眨” “怎么了手幢?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)忱详。 經(jīng)常有香客問(wèn)我围来,道長(zhǎng),這世上最難降的妖魔是什么踱阿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任管钳,我火速辦了婚禮,結(jié)果婚禮上软舌,老公的妹妹穿的比我還像新娘才漆。我一直安慰自己,他們只是感情好佛点,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布醇滥。 她就那樣靜靜地躺著,像睡著了一般超营。 火紅的嫁衣襯著肌膚如雪鸳玩。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,784評(píng)論 1 290
  • 那天演闭,我揣著相機(jī)與錄音不跟,去河邊找鬼。 笑死米碰,一個(gè)胖子當(dāng)著我的面吹牛窝革,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播吕座,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼虐译,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了吴趴?” 一聲冷哼從身側(cè)響起漆诽,我...
    開(kāi)封第一講書(shū)人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后厢拭,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體兰英,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年蚪腐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了箭昵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡回季,死狀恐怖家制,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情泡一,我是刑警寧澤颤殴,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站鼻忠,受9級(jí)特大地震影響涵但,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帖蔓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一矮瘟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧塑娇,春花似錦澈侠、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至写妥,卻和暖如春拳球,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背珍特。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工祝峻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人扎筒。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓呼猪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親砸琅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

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