最近手頭公司的**專案終於漸漸走出混沌,走上正軌,任務也輕鬆了一些,終於有時間整理和總結一下之前做的東西。
以往的專案一般使用模板引擎(如ejs)渲染出完整頁面,再傳送到瀏覽器展現。但這次專案的處理方式不同,整個專案由前端angularjs和後端nodejs進行了前後端的分離。後端nodejs提供靜態檔案服務和api介面,前端則通過ajax請求呼叫後端的api,已json資料報來進行資料交換。
同時,使用者許可權管理方面,我選用了rbac(基於角色的訪問控制,role-based access control)最基本的實現來管理(使用者表、角色表、許可權表、使用者-角色關聯表、角色-許可權關聯表)。而當我實際開發這個模組的時候,立刻就意識到和以往專案的區別:
在使用後端模板引擎渲染頁面的時候,後端可以根據使用者許可權有選擇地渲染一些受限的頁面元素。
而在前後端分離的開發方式下,由於後端並不渲染任何頁面,是否顯示某個頁面元素,完全是由前端來決定的。
對此,我考慮了一種相對簡單的方式:
將使用者最終所具有的所有許可權通過api返回給前端,前端根據許可權控制頁面元素。
後端本身就知道使用者許可權,每個api介面的入口處新增許可權的檢查。
然而,這樣的處理方式是有一定侷限性的:
後端每個api入口處都必須寫一遍檢查。
僅僅到許可權級別,太過寬泛,無法進行粒度更小的控制。
許可權雖然可以通過使用者、角色來實現可配置,但是許可權與頁面元素、api是否允許呼叫之間卻是由**編寫確定,這部分是無法配置的。
這顯然不是我能做到的最佳解決方案。
至少對於後端,我想要的是一種更加靈活可配置,並對業務**透明的許可權檢查方式。
於是,我在之前解決方案的基礎上,做了進一步細化,並將頁面元素、api都當作資源來看待。同時,為了前端可以做更加靈活的控制,頁面元素進一步抽象成乙份key-value資料(我稱之為頁面環境變數env),供前端使用。這樣,使用者經過rbac模組最終得到的不是許可權,而是「允許訪問的api列表(支援*和**通配)」和「環境變數」。
角色-許可權:
角色許可權
使用者基礎許可權
管理員管理員基礎許可權
使用者管理員
使用者管理員許可權
使用者管理員首頁
許可權-api路徑:
許可權api路徑
說明基礎許可權
/public/**
所有公共資源
/myaccount/**
個人賬戶所有操作
使用者管理員許可權
/manage/users/do/list
後台管理使用者列表
/manage/users/*/do/get
後台管理檢視任意使用者資訊
許可權-env環境變數:
許可權key
value
說明管理員基礎許可權
showmanagebtn
1顯示「管理」按鈕
pagesizeformanage
50後台管理列表頁行數
使用者管理員許可權
showmanageusersbtn
1後台管理顯示「使用者」按鈕
使用者管理員首頁
managehomepageurl
/main.html#/manage/users
後台管理頁面首頁位址
其中,使用者最終的api路徑表用於後端api進行許可權的檢查。env環境變數返回給前端供其控制頁面。
具體而言:
後端只要在請求入口(而不是單個api入口)處,對請求的url路徑和上面的「允許訪問的api路徑列表」進行比對。請求的路徑如在列表中,則通過檢查,之後的業務邏輯無需再關心許可權問題。如不在列表中,則直接返回拒絕請求。
前端則可以直接使用env環境變數中的key-value來控制頁面,
如配合angularjs的ng-show: ...
通過使用這種方式,不僅避免了對每個許可權進行 if...else 處理,同時,對後續修改及配置提供了相當大的便利。
當然,這種處理方式也有一些注意點(或者說缺點)。
1. api路徑設定要合理有規律,方便通配(單個星號通配1層路徑、兩個星號通配多層路徑)
統一路徑命名:如管理類介面都由/manage開頭,那麼在配置時,只需要使用/manage/**即可通配所有的路徑(包括:/manage/home、/manage/users/list)。
做好分層規劃:如管理類介面可以按功能細分 /manage/users/**、/manage/posts/**
以統一的動詞結尾:如唯讀許可權可以配置為/manage/**/do/get,新增許可權可以配置為/manage/**/do/add。
處理物件的id寫進路徑:如檢視使用者資訊的路徑為 /manage/users/1/do/get、/manage/users/2/do/get,可以配置許可權為/manage/users/*/do/get
2. 避免粒度過細
過細的粒度會導致api路徑以及env環境變數數量的暴增。不僅管理起來麻煩,而且也會一定程度上影響許可權檢查時的效率。
對於api路徑的粒度,一定要嚴格管理api路徑格式以及盡量使用通配,詳細見上述第1條。
對於env環境變數,可以考慮合併一些總是一起出現的內容。如系統只區分讀許可權和寫許可權,則新增、編輯、刪除按鈕的控制就可以合併為乙個 來處理,而不是為每個按鈕都新增乙個env環境變數。甚至可以將value設定為乙個json來儲存多個值 }
3. 設定不進行rbac認證的api路徑白名單
比如之前例子中的「基礎許可權」中的 /public/** 這類肯定允許訪問的路徑,其實是沒有必要特地新增乙個許可權來管理的。
這類api路徑應當寫到**配置中,作為不進行rbac認證的api路徑。
4. 對api路徑及env環境變數列表進行快取
每個請求都查詢資料庫來獲取api路徑列表顯然有點浪費資源。可以針對每個使用者,將api列表及環境變數儲存到session中,這樣只有第一次請求時才會查詢資料庫,之後的請求在rbac檢查許可權時,只需要從session取回之前快取的api列表和env環境變數即可。但要注意使用者許可權在改變時,需要及時令session中的資料失效。
我在專案中的做法是儲存進redis中,並以 cache@rbac#userid: 為key進行儲存。當使用者角色發生變化時,按照 cache@rbac#userid: 清除當前使用者的許可權快取即可;當角色、許可權、api路徑、env環境變數發生變化時,由於不是很好明確到底影響多少使用者,所以直接按照 cache@rbac#userid:* 來清除所有使用者的許可權快取。
總結:前後端分離的專案中,
1. 後端伺服器僅僅暴露api,所以功能級許可權管理可以處理為api的訪問控制。
2. 前端頁面需要從後端伺服器獲知如何控制頁面元素。同時,直接返回控制方式或具體數值可以減少前端 if...else 數量。
前後端分離專案中的坑
1 connectionabortederror winerror 10053 你的主機中的軟體中止了乙個已建立的連線。解決方式,ajax中async false ajax type post datatype json cache false,async false,headers content...
前後端分離專案
由於目前公司需要為已經存在的專案統一單點登入,而技術選型後採用的是apereo的cas。但是由於官方cas文件的混亂性 你懂得!並且其官方的例項和網上的例項教程都是基於傳統的專案 也就是非前後端分離專案 因此對於前後端分離的專案整合cas的可參考的資料就比較少,於是就有了下面的前後端分離專案基於ca...
前後端分離專案中前端如何呼叫後端介面?
前後端啟動專案,無法訪問介面。這是因為前後端的請求埠不一樣,如果是本地開發最簡單的方式就是禁用谷歌瀏覽器的安全策略,可以參考這裡。這個問題是跨域引起的,下面我們正式開始講關於跨域的問題。這裡我只推薦這兩種方式跨域,其它的跨域方式都還有很多但都不推薦,真心主流的也就這兩種方式。開發環境 生產環境 方案...