Django contrib auth authenticate函數(shù)源碼解析
引言
django提供了一個默認(rèn)的auth系統(tǒng)用于用戶的登錄和授權(quán),并提供了一定的擴展性,允許開發(fā)者自行定義多個驗證后臺,每個驗證后臺必須實現(xiàn)authenticate函數(shù),并返回None或者User對象。
默認(rèn)的后臺是django.contrib.auth.backends.ModelBackend,該后臺通過用戶名和密碼進(jìn)行用戶的驗證,以settings.AUTH_USER_MODEL作為模型。但是在實際的開發(fā)中,相信大家都不會固定的使用用戶名以及同一個model進(jìn)行驗證,比如,不同的角色需要不同的model作為驗證的數(shù)據(jù)源,有的角色是使用手機登錄,而有的角色使用郵箱登錄。
那么,當(dāng)存在多個驗證后臺的時候,django是如何制作一個統(tǒng)一的接口進(jìn)行不同后臺的驗證呢?
authenticate函數(shù)分析
源碼:
def authenticate(**credentials): ''' If the given credentials are valid, return a User object. ''' for backend, backend_path in _get_backends(return_tuples=True): try: inspect.getcallargs(backend.authenticate, **credentials) except TypeError: # This backend doesn’t accept these credentials as arguments. Try the next one. continue try: user = backend.authenticate(**credentials) except PermissionDenied: # This backend says to stop in our tracks - this user should not be allowed in at all. break if user is None: continue # Annotate the user object with the path of the backend. user.backend = backend_path return user # The credentials supplied are invalid to all backends, fire signal user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials))
**credentials
首先可以看到authenticate函數(shù)接受的參數(shù),這是指authenticate函數(shù)只接受關(guān)鍵字傳參,位置傳參是不允許的。因此在使用authenticate函數(shù)的時候注意不要為了省事而位置傳參。
# This will failuser = authenticate(’username’, ’password’)
# This will successuser = authenticate(username=’username’, password=’password’)
inspect.getcallargs(func, *args, **kwargs)inspect模塊是Python官方的標(biāo)準(zhǔn)模塊,這個模塊對Python的自省功能進(jìn)行一定的封裝。其中inspect.getcallargs檢查args和kwargs這些參數(shù)是否能被func要求的參數(shù)匹配,若匹配成功返回參數(shù)字典,如果不能匹配就會raise TypeError。舉個簡單的例子。假設(shè)在Python中定義這樣一個函數(shù):
import inspectdef test_func(arg1, arg2, *args, **kwargs): pass# this will raise TypeErrorinspect.getcallargs(test_func, a=1, b=2, c=3)# TypeError: test_func() missing 2 required positional arguments: ’arg1’ and ’arg2’# this will okinspect.getcallargs(test_func, 1, 2, 3, a=1, b=2, c=3)# {’kwargs’: {’b’: 2, ’c’: 3, ’a’: 1}, ’arg2’: 2, ’args’: (3,), ’arg1’: 1}
應(yīng)用場景
通過inspect.getcallargs的參數(shù)過濾功能,只要設(shè)置不同后臺的authenticate的函數(shù)參數(shù),就能在第一步實現(xiàn)不同角色的后臺選擇。
假設(shè)有三種角色,角色1使用用戶名登錄,角色2使用手機登錄,角色3使用手機或者郵箱登錄,那么如何通過inspect.getcallargs就選擇合適的backend.authenticate呢?
def role3_authenticate(role3_phone=None, role3_email=None, password=None): print('role1 authentication.')def role2_authenticate(role2_phone=None, password=None): print('role2 authenticate.')def role1_authenticate(role1_name=None, password=None): print('role2 authenticate.')methods = [role1_authenticate, role2_authenticate, role3_authenticate]def authenticate(**credentials): for backend in methods: try: inspect.getcallargs(backend, **credentials) except TypeError: print('error') continue backend(**credentials) print('end') break
如果加入**kwargs則每個authenticate都不會引發(fā)TypeError,因為其余參數(shù)都設(shè)置了默認(rèn)參數(shù),如果確實需要,則之前的參數(shù)使用位置傳參。
signal
若用戶沒有成功登陸,則authenticate發(fā)送了一個用戶沒有成功登陸的信號,開發(fā)者可以自行定義接受這個信號的recevier。關(guān)于django signal筆者之后還會詳細(xì)談及。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持好吧啦網(wǎng)。
相關(guān)文章:
1. XHTML 1.0:標(biāo)記新的開端2. CSS3實例分享之多重背景的實現(xiàn)(Multiple backgrounds)3. XML入門的常見問題(四)4. asp(vbscript)中自定義函數(shù)的默認(rèn)參數(shù)實現(xiàn)代碼5. 詳解瀏覽器的緩存機制6. php網(wǎng)絡(luò)安全中命令執(zhí)行漏洞的產(chǎn)生及本質(zhì)探究7. XML解析錯誤:未組織好 的解決辦法8. 使用Spry輕松將XML數(shù)據(jù)顯示到HTML頁的方法9. 利用CSS3新特性創(chuàng)建透明邊框三角10. ASP基礎(chǔ)知識VBScript基本元素講解
