CurrentUser,也就是當(dāng)前用戶,這是我們系統(tǒng)中大量使用的一個(gè)概念。
確認(rèn)當(dāng)前用戶
當(dāng)然,我們利用的是cookie:用戶的ID存放在cookie中,服務(wù)器端通過cookie中的Id,查找數(shù)據(jù)庫,得到需要的用戶信息。
那么,這里就有一個(gè)安全問題,如何防止cookie的偽造或篡改?我們采用了以下方法:
首先,cookie中除了存放用戶Id,還存放了一個(gè)加密過后的驗(yàn)證碼,其來源如下:
49b5f37dff119cf81fcb2b4e6077e17;
所以,當(dāng)服務(wù)器端使用cookie中的用戶Id時(shí),會先檢查加密過后的驗(yàn)證碼是否有效。捏造的驗(yàn)證碼是不會通過審核的。
還有一點(diǎn)需要說明的是,我們不考慮一個(gè)有效的cookie(連同驗(yàn)證碼)被盜竊的情形。因?yàn)檫@就相當(dāng)于你的電腦被別人使用了一樣,我們確實(shí)無法判斷使用你電腦的是不是你本人。
為什么沒有使用session
可能有同學(xué)會想到,每次取cookie再查數(shù)據(jù)庫,是不是會增加數(shù)據(jù)庫負(fù)擔(dān),為什么不考慮session呢?兩個(gè)方面的原因:
CurrentUser的ViewModel
CurrentUser最麻煩的一件事情是:很多頁面是根據(jù)不同的當(dāng)前用戶,顯示不同的內(nèi)容的。以“任務(wù)編輯”頁面為例,當(dāng)前用戶是該任務(wù)的發(fā)布人,發(fā)布欄可編輯;否則,發(fā)布欄僅僅是可讀的。
所以,最初我們的方案很簡單,也封裝一個(gè)CurrentUserModel就可以了呀!
但后來我們發(fā)現(xiàn):
在MVC架構(gòu)中,Controller將Model傳遞給View,其實(shí)可能有兩種情況:
我曾經(jīng)計(jì)劃禁止掉第2種情形,也就是說:在View里面不需要任何計(jì)算,只負(fù)責(zé)呈現(xiàn)。用代碼表示就是:
@if (Model.CurrentUserIsAccepter){
//CurrentUserIsAccepter的值在controller中獲取}
而不是之前的:
@if (Model.CurrentUser.Id == Model.Accepter.Id){}
但我們最終放棄了,因?yàn)閷?shí)現(xiàn)起來太臃腫了。我們可以想象,這樣的話,我們首先就至少需要三個(gè)Is屬性:
public class EditModel { public bool IsAccepter { get; set; } public bool IsOwner { get; set; } public bool IsPublisher { get; set; } }
有點(diǎn)怪,但好像還可以接受,但后來情況發(fā)生了變化,我們還得考慮當(dāng)前用戶即是發(fā)布人又是承接人,或者即是承接人又是驗(yàn)收人,或者既是……又是……的情形:
public class EditModel { public bool IsAccepter { get; set; } public bool IsOwner { get; set; } public bool IsPublisher { get; set; } public bool IsBothAccepterAndOwner { get; set; } public bool IsBothAccepterAndPublisher { get; set; } public bool IsBothPublisherAndOwner { get; set; } //...... }
這代碼給人的感覺就是有病了。關(guān)鍵是,誰知道以后還來不來一個(gè)“是…和…但不是……”的邏輯呢?到時(shí)候又該怎么辦呢?
//任務(wù)編輯頁面(/Task/Edit/{taskId})是一個(gè)頁面呈現(xiàn)邏輯比較復(fù)雜的典型例子,我們前后大改了三次,才形成今天所使用的代碼格局。//我以前說我?guī)У囊粋€(gè)妹紙看著代碼哭,哭的就是這里,呵呵//有興趣的同學(xué)可以研究一下。
所以,取巧是不行了,我們還是得面對這個(gè)問題:
如何劃分Controller和View之間的邏輯/責(zé)任?
更直白一點(diǎn)的講,哪些事該Controller做,哪些事該View做?這個(gè)問題真的超級虐心。我想來想去,只能說:“能Controller做的,盡量讓Controller做”。我自己對這個(gè)問題都相當(dāng)不滿意,但實(shí)在是沒有辦法啦。
具體到CurrentUser的ViewModel,我們提出以下兩個(gè)原則:
為什么需要明確這些原則
可能你耐著性子看了上面的分析,最后卻只得到一個(gè)似是而非又蛋疼的原則,會忍不住的問,“為什么一定需要/講解這些原則?讓程序員根據(jù)實(shí)際情況,自由發(fā)揮,不行么?”
淺層次的原因是要保證代碼的可讀性。閱讀別人的代碼是一件非常累的事情。但如果所有的代碼都像一個(gè)人寫的,而且這個(gè)人的思路自始至終都是非常清晰的,這樣,我們會稍稍輕松一點(diǎn)。代碼不是文學(xué)作品,在絕大多數(shù)情況下,不能天馬行空自由發(fā)揮!
我們很多開發(fā)人員都已經(jīng)開始注意代碼的規(guī)范,但大多數(shù)還停留在縮進(jìn)、換行、命名之類的細(xì)節(jié)(當(dāng)然,這些也很重要)上;而架構(gòu)師應(yīng)站在一個(gè)更全局的高度,來“規(guī)范”所有的開發(fā)行為。
所以,其實(shí)更深層次的原因是:所有的代碼都必須規(guī)范化。既然要規(guī)范化,那么首先就要有規(guī)范!先可以不管好壞,但至少要有。那么怎么制定完善這個(gè)規(guī)范呢?我分享一下我的經(jīng)驗(yàn):
這樣不斷的迭代,基本上就能不斷的提高代碼的規(guī)范性,并得到一份不錯的規(guī)范文檔。
好像寫跑題了,又是項(xiàng)目管理方向的東西。就先這樣吧!前臺的架構(gòu),想想,剩下的應(yīng)該就是單元測試(都還沒做,所以暫時(shí)也講不了),還有可能其他一些細(xì)節(jié)了,以后查漏補(bǔ)缺吧。接下來希望參與到項(xiàng)目的前臺開發(fā)的同學(xué)就可以開始聯(lián)系我了。博客系列我們將接著講Service層。