新聞中心
我是學(xué)院講師Alex(李杰),在學(xué)院“4.20 IT充電節(jié)”(4月19~20日)到來(lái)之際,和大家分享一下Django之路。正文來(lái)啦~~~

創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),容縣企業(yè)網(wǎng)站建設(shè),容縣品牌網(wǎng)站建設(shè),網(wǎng)站定制,容縣網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷(xiāo),網(wǎng)絡(luò)優(yōu)化,容縣網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M(mǎn)足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專(zhuān)業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶(hù)成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
業(yè)務(wù)場(chǎng)景分析
假設(shè)我們?cè)陂_(kāi)發(fā)一個(gè)培訓(xùn)機(jī)構(gòu)的客戶(hù)關(guān)系管理系統(tǒng),系統(tǒng)分客戶(hù)管理、學(xué)員管理、教學(xué)管理3個(gè)大模塊,每個(gè)模塊大體功能如下:
客戶(hù)管理
銷(xiāo)售人員可以錄入客戶(hù)信息,對(duì)客戶(hù)進(jìn)行跟蹤,為客戶(hù)辦理報(bào)名手續(xù)
銷(xiāo)售人員可以修改自己錄入的客戶(hù)信息
客戶(hù)信息不能刪除
銷(xiāo)售主管可以查看銷(xiāo)售報(bào)表
學(xué)員管理
學(xué)員可以在線(xiàn)報(bào)名
學(xué)員可以查看自己的報(bào)名合同、學(xué)習(xí)有效期
學(xué)員可以在線(xiàn)提交作業(yè)、查看自己的成績(jī)
教學(xué)管理
管理員可以創(chuàng)建新課程、班級(jí)
講師可以創(chuàng)建上課紀(jì)錄
講師可以在線(xiàn)點(diǎn)名、批作業(yè)
從上面的需求中,我們至少提取出了5個(gè)角色,普通銷(xiāo)售、銷(xiāo)售主管、學(xué)員、講師、管理員,他們能做的事情都是不一樣的。
如何設(shè)計(jì)一套權(quán)限組件來(lái)實(shí)現(xiàn)對(duì)上面各種不同功能進(jìn)行有效的權(quán)限控制呢?我們肯定不能LOW到為每個(gè)動(dòng)作都一堆代碼來(lái)控制權(quán)限,對(duì)吧?這些表面上看著各種不盡相同的功能,肯定是可以提取出一些相同的規(guī)律的,仔細(xì)分析,其實(shí)每個(gè)功能本質(zhì)上都是一個(gè)個(gè)的動(dòng)作,如果能把動(dòng)作再抽象出具體權(quán)限條目,然后把這些權(quán)限條目再跟用戶(hù)關(guān)聯(lián),每個(gè)用戶(hù)進(jìn)行這個(gè)動(dòng)作,就檢查他沒(méi)有這個(gè)權(quán)限,不就實(shí)現(xiàn)權(quán)限的控制了么?由于這個(gè)系統(tǒng)是基于Web的B/S架構(gòu),我們可以把每個(gè)動(dòng)作的構(gòu)成提取成以下的元素。
一個(gè)動(dòng)作 = 一條權(quán)限 = 一個(gè)url + 一種請(qǐng)求方法(get/post/put...) + 若干個(gè)請(qǐng)求參數(shù)
那我們接下來(lái)需要做的,就是把一條條的權(quán)限條目定義出來(lái),然后跟用戶(hù)關(guān)聯(lián)上就可以了!
開(kāi)發(fā)中需要的權(quán)限定義
什么是權(quán)限?
權(quán)限就是對(duì)軟件系統(tǒng)中各種資源的訪(fǎng)問(wèn)和操作的控制!
什么是資源?
在軟件系統(tǒng)中,數(shù)據(jù)庫(kù)、內(nèi)存、硬盤(pán)里數(shù)據(jù)都是資源,資源就是數(shù)據(jù)!
動(dòng)作
資源本身是靜態(tài)的,必須通過(guò)合適的動(dòng)作對(duì)其進(jìn)行訪(fǎng)問(wèn)和操作,我們說(shuō)要控制權(quán)限,其實(shí)本質(zhì)上是要對(duì)訪(fǎng)問(wèn)軟件中各種數(shù)據(jù)資源的動(dòng)作進(jìn)行控制 。
動(dòng)作又可以分為2種:
資源操作動(dòng)作:訪(fǎng)問(wèn)和操作各種數(shù)據(jù)資源,比如訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)或文件里的數(shù)據(jù)。
業(yè)務(wù)邏輯事件動(dòng)作:訪(fǎng)問(wèn)和操作的目的不是數(shù)據(jù)源本身,而是借助數(shù)據(jù)源而產(chǎn)生的一系列業(yè)務(wù)邏輯,比如批量往遠(yuǎn)程主機(jī)上上傳一個(gè)文件,你需要從數(shù)據(jù)庫(kù)中訪(fǎng)問(wèn)主機(jī)列表,但你真正要操作的是遠(yuǎn)程的主機(jī),這個(gè)遠(yuǎn)程的主機(jī),嚴(yán)格意義上來(lái)并不是你的數(shù)據(jù)資源,而是這個(gè)資源代表的實(shí)體。
權(quán)限授權(quán)
權(quán)限的使用者可以是具體的個(gè)人、亦可以是其他程序,這都沒(méi)關(guān)系,我們可以把權(quán)限的授權(quán)主體,統(tǒng)稱(chēng)為用戶(hù),無(wú)論這個(gè)用戶(hù)后面是具體的人,還是一個(gè)程序,對(duì)權(quán)限控制組件來(lái)講,都不影響。
權(quán)限必然是需要分組的,把一組權(quán)限分成一個(gè)組,授權(quán)給特定的一些用戶(hù),分出來(lái)的這個(gè)組,就可以稱(chēng)為角色。
權(quán)限應(yīng)該是可以疊加的!
權(quán)限組件的設(shè)計(jì)與代碼實(shí)現(xiàn)
我們把權(quán)限組件的實(shí)現(xiàn)分3步,權(quán)限條目的定義,權(quán)限條目與用戶(hù)的關(guān)聯(lián),權(quán)限組件與應(yīng)用的結(jié)合。
權(quán)限條目的定義
我們前面講過(guò)以下概念,現(xiàn)在需要做的,就是把我們系統(tǒng)中所有的需要控制的權(quán)限所對(duì)應(yīng)的動(dòng)作提取成一條條 url+請(qǐng)求方法+參數(shù)的集合就可以。
一個(gè)動(dòng)作 = 一條權(quán)限 = 一個(gè)url + 一種請(qǐng)求方法(get/post/put...) + 若干個(gè)請(qǐng)求參數(shù)
以下是提取出來(lái)的幾條權(quán)限
- perm_dic={
- 'crm_table_index':['table_index','GET',[],{},], #可以查看CRM APP里所有數(shù)據(jù)庫(kù)表
- 'crm_table_list':['table_list','GET',[],{}], #可以查看每張表里所有的數(shù)據(jù)
- 'crm_table_list_view':['table_change','GET',[],{}],#可以訪(fǎng)問(wèn)表里每條數(shù)據(jù)的修改頁(yè)
- 'crm_table_list_change':['table_change','POST',[],{}], #可以對(duì)表里的每條數(shù)據(jù)進(jìn)行修改
- }
字典里的key是權(quán)限名,一會(huì)我們需要用過(guò)這些權(quán)名來(lái)跟用戶(hù)進(jìn)行關(guān)聯(lián)。
后面values列表里***個(gè)值如'table_index'是django中的url name,在這里必須相對(duì)的url name, 而不是絕對(duì)url路徑,因?yàn)榭紤]到django url正則匹配的問(wèn)題,搞絕對(duì)路徑,不好控制。
values里第2個(gè)值是http請(qǐng)求方法。
values里第3個(gè)[]是要求這個(gè)請(qǐng)求中必須帶有某些參數(shù),但不限定對(duì)數(shù)的值是什么。
values里的第4個(gè){}是要求這個(gè)請(qǐng)求中必須帶有某些參數(shù),并且限定所帶的參數(shù)必須等于特定的值。
有的同學(xué)看了上面的幾條權(quán)限定義后,提出疑問(wèn),說(shuō)你這個(gè)權(quán)限的控制好像還是粗粒度的,比如我想控制用戶(hù)只能訪(fǎng)問(wèn)客戶(hù)表里的一條或多條特定的用戶(hù)怎么辦?
哈,這個(gè)問(wèn)題很好,但很容易解決呀,只需要在[] or {}里指定參數(shù)就可呀,比如要求http請(qǐng)求參數(shù)中必須包括指定的參數(shù),舉個(gè)例子,我的客戶(hù)表如下:
Customer表
里面的status字段是用來(lái)區(qū)分客戶(hù)是否報(bào)名的,我現(xiàn)在的需求是,只允許用戶(hù)訪(fǎng)問(wèn)客戶(hù)來(lái)源為qq群且已報(bào)名的客戶(hù),你怎么控制?
通過(guò)分析我們得出,這個(gè)動(dòng)作的url為
- http://127.0.0.1:9000/kingadmin/crm/customer/?source=qq&status=signed
客戶(hù)來(lái)源參數(shù)是source,報(bào)名狀態(tài)為status,那我的權(quán)限條目就可以配置成
- 'crm_table_list':['table_list','GET',[],{'source':'qq', 'status':'signed'}]
權(quán)限條目與用戶(hù)的關(guān)聯(lián)
我們并沒(méi)有像其他權(quán)限系統(tǒng)一樣把權(quán)限定義的代碼寫(xiě)到了數(shù)據(jù)里了,也許是因?yàn)槲覒?,不想花時(shí)間去設(shè)計(jì)存放權(quán)限的表結(jié)構(gòu),but anyway,基于現(xiàn)有的設(shè)計(jì),我們?nèi)绾伟褭?quán)限條目與用戶(hù)關(guān)聯(lián)起來(lái)呢?
good news is 我們可以直接借用django自帶的權(quán)限系統(tǒng),大家都知道 django admin 自帶了一個(gè)簡(jiǎn)單的權(quán)限組件,允許把用戶(hù)在使用admin過(guò)程中控制到表級(jí)別的增刪改查程度,但沒(méi)辦法對(duì)表里的某條數(shù)據(jù)控制權(quán)限,即要么允許訪(fǎng)問(wèn)整張表,要么不允許訪(fǎng)問(wèn),實(shí)現(xiàn)不了只允許用戶(hù)訪(fǎng)問(wèn)表中的特定數(shù)據(jù)的控制。
我們雖然沒(méi)辦法對(duì)通過(guò)自帶的django admin 權(quán)限系統(tǒng)實(shí)現(xiàn)想要的權(quán)限控制,但是可以借用它的權(quán)限與用戶(hù)的關(guān)聯(lián)邏輯!自帶的權(quán)限系統(tǒng)允許用戶(hù)添加自定義權(quán)限條目,方式如下:
- class Task(models.Model):
- ...
- class Meta:
- permissions = (
- ("view_task", "Can see available tasks"),
- ("change_task_status", "Can change the status of tasks"),
- ("close_task", "Can remove a task by setting its status as closed"),
- ) 這樣就添加了3條自定義權(quán)限的條目,然后 manage.py migrate 就可以在django自帶的用戶(hù)表里的permissions字段看到你剛添加的條目。
只要把剛添加的幾條權(quán)限移動(dòng)的右邊的框里,那這個(gè)用戶(hù)就相當(dāng)于有相應(yīng)的權(quán)限了!以后,你在代碼里通過(guò)以下語(yǔ)句,就可以判定用戶(hù)是否有相應(yīng)的權(quán)限。
- user.has_perm('app.view_task')
看到這,有的同學(xué)還在蒙逼,這個(gè)自帶的權(quán)限跟我們剛才自己定義的權(quán)限條目有半毛錢(qián)關(guān)系么?聰明的同學(xué)已經(jīng)看出來(lái)了, 只要我們把剛才自己定義的perm_dic字典里的所有key在這個(gè)META類(lèi)的permissions元組里。就相當(dāng)于把用戶(hù)和它可以操作的權(quán)限關(guān)聯(lián)起來(lái)了!這就省掉了我們必須自己寫(xiě)權(quán)限與用戶(hù)關(guān)聯(lián)所需要的代碼了。
權(quán)限組件與應(yīng)用的結(jié)合
我們希望我們的權(quán)限組件是通用的,可插拔的,它一定要與具體的業(yè)務(wù)代碼分離,以后可以輕松把這個(gè)組件移植到其他的項(xiàng)目里去,因此這里我們采用裝飾器的模式,把權(quán)限的檢查、控制封裝在一個(gè)裝飾器函數(shù)里,想對(duì)哪個(gè)Views進(jìn)行權(quán)限控制,就只需要在這個(gè)views上加上裝飾器就可以了。
- @check_permission
- def table_change(request,app_name,table_name,obj_id):
- .....
那這個(gè)@check_permission裝飾器里干的事情,就是以下幾步:
1.拿到用戶(hù)請(qǐng)求的url+請(qǐng)求方法+參數(shù)到我們的的perm_dic里去一一匹配。
2.當(dāng)匹配到了對(duì)應(yīng)的權(quán)限條目后,就拿著這個(gè)條目所對(duì)應(yīng)的權(quán)限名,和當(dāng)前的用戶(hù),調(diào)用request.user.has_perm(權(quán)限名)。
3.如果request.user.has_perm(權(quán)限名)返回為T(mén)rue,就認(rèn)為該用戶(hù)有權(quán)限,直接放行,否則,則返回403頁(yè)面!
權(quán)限檢查代碼
加入自定義權(quán)限
仔細(xì)按上面的步驟走下來(lái),并玩了一會(huì)的同學(xué),可能會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,這個(gè)組件對(duì)有些權(quán)限是控制不到的,就是涉及到一些業(yè)務(wù)邏輯的權(quán)限,沒(méi)辦法控制, 比如我只允許用戶(hù)訪(fǎng)問(wèn)自己創(chuàng)建的客戶(hù)數(shù)據(jù),這個(gè)你怎么控制?
通過(guò)控制用戶(hù)的請(qǐng)求參數(shù)是沒(méi)辦法實(shí)現(xiàn)的,因?yàn)槟惬@取到的request.user是個(gè)動(dòng)態(tài)的值,你必須通過(guò)代碼來(lái)判斷這條數(shù)據(jù)是否是由當(dāng)前請(qǐng)求用戶(hù)創(chuàng)建的。類(lèi)似的業(yè)務(wù)邏輯還有很多?你怎么搞?
仔細(xì)思考了10分鐘,既然這里必須涉及到允許開(kāi)發(fā)人員通過(guò)自定義一些業(yè)務(wù)邏輯代碼來(lái)判斷用戶(hù)是否有權(quán)限的話(huà),那我在我的權(quán)限組件里再提供一個(gè)權(quán)限自定義函數(shù)不就可以了,開(kāi)發(fā)者可以把自定的權(quán)限邏輯寫(xiě)到函數(shù)里,我的權(quán)限組件自動(dòng)調(diào)用這個(gè)函數(shù),只要返回為T(mén)rue就認(rèn)為有權(quán)限,就可以啦!
加入了自定義權(quán)限鉤子的代碼
權(quán)限配置條目
- 'crm_can_access_my_clients':['table_list','GET',[],
- {'perm_check':33,'arg2':'test'},
- custom_perm_logic.only_view_own_customers],
看***面我們加入的only_view_own_customers就是開(kāi)發(fā)人員自已加的權(quán)限控制邏輯,里面想怎么寫(xiě)就怎么寫(xiě)。
- def only_view_own_customers(request,*args,**kwargs):
- print('perm test',request,args,kwargs)
- consultant_id = request.GET.get('consultant')
- if consultant_id:
- consultant_id = int(consultant_id)
- print("consultant=1",type(consultant_id))
- if consultant_id == request.user.id:
- print("\033[31;1mchecking [%s]'s own customers, pass..\033[0m"% request.user)
- return True
- else:
- print("\033[31;1muser can only view his's own customer...\033[0m")
- return False
這樣,萬(wàn)通且通用的權(quán)限框架就開(kāi)發(fā)完畢了,權(quán)限的控制粒度,可粗可細(xì)、可深可淺,包君滿(mǎn)意!以后要移植到其它django項(xiàng)目時(shí),你唯一需要改的,就是配置好perm_dic里的權(quán)限條目!
學(xué)院 4.20 IT充電節(jié)
(19-20號(hào)兩天,100門(mén)視頻課程免單搶?zhuān)幸曨l課程會(huì)員享6折,非會(huì)員享7折,套餐折上8折,微職位立減2000元鉅惠)
活動(dòng)鏈接:http://edu./activity/lists/id-47.html?wenzhang
相關(guān)視頻教程:
Python運(yùn)維自動(dòng)化開(kāi)發(fā)視頻課程套餐
http://edu./pack/view/id-291.html
分享標(biāo)題:Django之路如何開(kāi)發(fā)通用且萬(wàn)能的的權(quán)限框架組件
分享地址:http://www.5511xx.com/article/cdjesgg.html


咨詢(xún)
建站咨詢(xún)
