最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解從Django Allauth中進(jìn)行登錄改造小結(jié)

 更新時(shí)間:2019年12月18日 08:26:47   作者:敖天羽  
這篇文章主要介紹了從 Django Allauth 中進(jìn)行登錄改造小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

大概來(lái)介紹一下 Django Allauth 改造的期間遇到的一些問(wèn)題和改造方法,在此之前我只想說(shuō)——Django Allauth 是屑。

為什么我說(shuō) Django Allauth 是屑

入職之初我就接到了一些第三方登錄的任務(wù),然而 Django Allauth 將內(nèi)部封裝的太好,暴露的 API 不足,更新又慢,issue 和 PR 很少有人處理,當(dāng)你需要擴(kuò)展時(shí),很多情況下你只能用一些 hack 的手段去解決問(wèn)題,非常蛋疼,所以當(dāng)時(shí)就決定慢慢的切到自己的一套 Auth 體系中。

目前已經(jīng)做的是第三方登錄的部分,賬號(hào)管理的部分還沒(méi)有遷移,之前稍微看了一下,要遷移的成本還是比較麻煩的。

遷移成本在哪里

Django 中的賬號(hào)密碼登錄一般是由本身提供的 auth 表進(jìn)行擴(kuò)展的結(jié)果,而 allauth 在此基礎(chǔ)上擴(kuò)充了第三方登錄的幾個(gè)表,再和本身的 auth user 表關(guān)聯(lián)。而這一部分是構(gòu)建在 Allauth 內(nèi)部的 model 內(nèi),且沒(méi)有暴露任何的方法來(lái)修改結(jié)構(gòu)(當(dāng)然可能也是因?yàn)檎娴牟缓酶模?,?dǎo)致一旦不滿(mǎn)足需求就很難搞,因?yàn)閿?shù)據(jù)已經(jīng)放在那里了,刷數(shù)據(jù)同步的方案對(duì)于大流量網(wǎng)站來(lái)說(shuō)也并不是很友好的選擇。

此外,在路由上,由于我們需要盡可能的無(wú)痛遷移和在漸進(jìn)式切換時(shí)的平穩(wěn)降級(jí),因此只能通過(guò)簡(jiǎn)單粗暴的路由覆蓋操作,這極度依賴(lài)路由的解析順序。

數(shù)據(jù)庫(kù)擴(kuò)展與 provider 變更

說(shuō)了這么多,其實(shí)關(guān)鍵點(diǎn)并不在于「問(wèn)題在哪里」,而在于「我是怎么解決這些問(wèn)題的」。

Allauth 一個(gè)平臺(tái)的注冊(cè)是一個(gè) provider,比如 「wechat」、「weibo」、「qq」,整張表是一對(duì)一的關(guān)系,那么問(wèn)題來(lái)了,我們知道,國(guó)內(nèi)的平臺(tái)往往并不是一個(gè) appid 和 key 能搞定的事情,對(duì)于 web 和移動(dòng)端的平臺(tái)來(lái)說(shuō),其實(shí)是兩個(gè) appid 共享一套 unionid,盡管官方提供了一套增加 Provider 的擴(kuò)展方式,但實(shí)際上是沒(méi)有必要的,因?yàn)?Web 和移動(dòng)端來(lái)說(shuō),獲得用戶(hù)信息的接口是共享的,而移動(dòng)端并不用通過(guò)后端獲取 access_token。在綁定上,實(shí)際上也是同一個(gè)平臺(tái)。

因此我們擴(kuò)充了一張表來(lái)解決這個(gè)問(wèn)題,將我們額外的信息放在了額外添加的表中。

之后要解決的就是 admin 的 provider select 問(wèn)題,它會(huì)進(jìn)行一次校驗(yàn),所以我們必須要取消這些校驗(yàn)并把 select 改成 input。

首先,我們要取消 Model 層的校驗(yàn), Proxy 可以對(duì)表進(jìn)行一些覆蓋式的操作(但不能改變表結(jié)構(gòu)):

class CustomSocialApp(SocialApp):
  class Meta:
    proxy = True

  def clean_fields(self, exclude=None):
    # 別校驗(yàn)了
    pass

  def full_clean(self, exclude=None, validate_unique=True):
    # 別校驗(yàn)了
    pass

  def clean(self, exclude=None, validate_unique=True):
    # 別校驗(yàn)了
    pass

這里我們?cè)谠瓉?lái)的 SocialApp 的基礎(chǔ)上新建一個(gè)屬于自己的新的 Admin,他本質(zhì)上還是操作 SocialApp 表,只是挪出來(lái)方便我們自定義而已:

class CustomSocialAppAdmin(SocialAppAdmin):
  list_display = ('provider_text', 'name')
  form = CustomAppAdminForm

  def get_form(self, request, obj=None, **kwargs):
    kwargs['widgets'] = {'provider': forms.TextInput}
    return super().get_form(request, obj, **kwargs)

  def provider_text(self, obj):
    return obj.provider

但是這樣就會(huì)遇到一個(gè) provider 的校驗(yàn)問(wèn)題,這也就是上面我們還沒(méi)有寫(xiě)完的 CustomAppAdminForm 的部分,我們將校驗(yàn)的部分用自定義的 form 完全取消:

class CustomSocialAppAdminForm(forms.ModelForm):
  class Meta:
    model = CustomSocialApp
    fields = '__all__'
    widgets = {'provider': forms.TextInput()}

  def clean(self):
    # 別校驗(yàn)了
    if self.has_error('provider'):
      del self._errors['provider']
    self.cleaned_data['provider'] = self.data['provider']
    return self.cleaned_data

這樣就完成了校驗(yàn)的修改,成了一個(gè)完全體的 input 覆蓋了原來(lái)的 select。

第三方登錄與綁定流程

上面可以任意在表中拓展 provider 了 ,但重頭戲其實(shí)是:搞清楚 allauth 原本的登錄和綁定流程,完美的 copy 一份流程,這樣才能實(shí)現(xiàn)平穩(wěn)降級(jí)和無(wú)痛遷移。

查找賬號(hào)

  1. 獲取用戶(hù)授權(quán)信息中的 uid
  2. 在 AllauthSocialAccount 表中獲取到對(duì)應(yīng)的數(shù)據(jù),如果沒(méi)有則返回 None

登錄流程

  1. 確保用戶(hù)是匿名用戶(hù):request.user.is_anouymous 且已經(jīng)存在對(duì)應(yīng)的賬號(hào)
  2. 更新 AllauthSocialAccount 表中的數(shù)據(jù)到最新
  3. 根據(jù) social account 更新 social token
  4. 寫(xiě)入 session(Django 中自帶 login 函數(shù))

注冊(cè)流程

  1. 確保用戶(hù)是匿名用戶(hù)且不存在對(duì)應(yīng)賬號(hào)
  2. 創(chuàng)建新用戶(hù)(要點(diǎn)是生成用戶(hù)名和昵稱(chēng)),在 Django 中有 create_user 可以直接創(chuàng)建
  3. 寫(xiě)入 AllatuhSocialAccount 和 AllauthSocialToken
  4. 寫(xiě)入 session 登錄

綁定流程

  • 用戶(hù)不是匿名用戶(hù)
  • 查找對(duì)應(yīng)的第三方賬號(hào)是否已經(jīng)被綁定
  • 更新 AllauthSocialAccount 表
  • 更新 social token

只要按照這個(gè)流程實(shí)現(xiàn)下來(lái)就可以了,而同一平臺(tái)多 provider(appid)的差異功能與核心部分無(wú)關(guān),可以在各社交媒體對(duì)應(yīng)的文件中單獨(dú)實(shí)現(xiàn)。

構(gòu)建新的賬號(hào)系統(tǒng)

現(xiàn)在我們徹底將第三方登錄抽離了出來(lái),接下來(lái)需要抽出賬號(hào)的部分,賬號(hào)登錄和注冊(cè)本質(zhì)上還是 Django 提供的那些東西,因此比較好抽,需要兼容的部分主要在于「忘記密碼」和「重置密碼」。

我們來(lái)思考一下為什么這部分需要做兼容:

一般來(lái)說(shuō)我們都是在重置密碼時(shí)在手機(jī)或者郵箱里收到一個(gè)驗(yàn)證郵件,里面會(huì)附上一個(gè)隨機(jī)字符串用來(lái)保證連接的唯一性。而在我們替換過(guò)程中,我們不能讓一群用戶(hù)已經(jīng)發(fā)送過(guò)但還沒(méi)有使用的隨機(jī)字符串不可用,從可讀的角度來(lái)看,生成的內(nèi)容也應(yīng)該和原來(lái)差不多(同時(shí)也是避免沖突),因此需要抄一下它的忘記密碼。

在 account/forms 中表明了 token 的生成算法:

from django.contrib.auth.tokens import PasswordResetTokenGenerator
token_generator = PasswordResetTokenGenerator()
# 生成 token
key = token_generator.make_token(user)
# 檢查 token
token_generator.check_token(user, key)

Allauth 中將 user 用 base36 加密了,兼容 Python2,所以 utils 中的語(yǔ)句略長(zhǎng),由于我們直接是 Python3,所以只剩下這些句子:

from django.utils.http import base36_to_int
from django.utils.http import int_to_base36


def user_pk_to_url_str(user):
  return int_to_base36(user.pk)


def url_str_to_user_pk(s):
  return base36_to_int(s)

所有內(nèi)容將會(huì)被存儲(chǔ)在 account_emailconfirmation 表中,這樣就能保證對(duì)應(yīng)的關(guān)系了。

總結(jié)

在賬號(hào)的部分由于還沒(méi)有改完,所以可以說(shuō)的不多,只是做了一些微小的工作,對(duì)于這種可能需要根據(jù)國(guó)情定制的需求,建議大家還是小心使用。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論

宁明县| 喀什市| 和静县| 广饶县| 罗山县| 墨玉县| 阳曲县| 浑源县| 台北市| 大兴区| 永吉县| 盈江县| 木里| 资阳市| 杭锦后旗| 来安县| 安西县| 朝阳县| 阜康市| 余江县| 竹山县| 务川| 英山县| 双辽市| 加查县| 永胜县| 南丹县| 资溪县| 绍兴县| 和平县| 天祝| 东海县| 兴山县| 靖州| 德保县| 应用必备| 晴隆县| 山东省| 星座| 木兰县| 宁国市|