最近接手一小型私活,用戶量封頂上千,工期預期的也相對寬鬆,權限控制固然是必不可少。git
web 權限控制,不少項目會引入 shiro/spring-security。web
shiro/spring-security 繼承 servlet-->filter抽象接口,運用合適的設計模式,spring
經過攔截客戶端請求,來實現各個角色對系統資源的訪問權限。數據庫
一時興起,有了本身實現權限控制的想法,遂有此文,若是你用膩了 shiro/spring-security,不妨來和我一塊兒完善它。apache
本文只作拋磚引玉之用,重點在思路,具體項目具體編程語言請自行拿捏。編程
Git Demo:https://git.oschina.net/LanboEx/simple-auth-demo設計模式
Shiro 中定義攔截過濾鏈,能夠很簡單實現上圖中的想法,像下面這種姿式(但咱的目的是本身動手)。restful
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> ............ <!-- 過濾鏈定義 --> <property name="filterChainDefinitions"> <value> <!--anno:AnonymousFilter 不須要任何權限便可訪問--> /login.jsp* = anon /login.do* = anon <!--authc:FormAuthenticationFilter 表單驗證權限--> /pages/* = authc /index.jsp* = authc <!--perms:PermissionsAuthorizationFilter 指定受權訪問--> /role/edit/* = perms[role:edit] /role/save = perms[role:edit] /role/list = perms[role:view] </value> </property> </bean>
想法大體和 shiro/spring-security 相同,實現 Filter 接口攔截客戶端的對應請求。session
比較有意思的部分,首先你得肯定該 Filter 須要攔截什麼的請求,服務? 靜態頁面 ? 交互腳本?網頁樣式?圖片?app
固然項目須要有良好的命名規範,不管是 restful 風格或傳統風格。規範項目中的請求 URL 或添加特定的後綴。web.xml 配置好比像下面。
<filter> <filter-name>simpleAuthFilter</filter-name> <filter-class>com.rambo.sad.SimpleAuthFilter</filter-class> <init-param> <param-name>defaultPage</param-name> <param-value>/view/login.jsp</param-value> </init-param> <init-param> <param-name>freeServices</param-name> <param-value> /view/login.jsp,login.do <!--登陸相關--> </param-value> </init-param> </filter> <filter-mapping> <filter-name>simpleAuthFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> <filter-mapping> <filter-name>simpleAuthFilter</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping>
其次你須要肯定該本次請求是否有訪問該資源的權限,我項目中肯定邏輯比較簡單,畢竟千人系統。
將登陸頁面和登陸請求作爲 FreeService ,也就是暴露在系統外的資源,登陸時在 Session 中放置對應登陸對象 PO。
既方便系統內的相應展現,也可作爲用戶是否登陸的憑證,好比登陸服務邏輯像下面。
@RequestMapping("/login.do") public String login(HttpSession httpSession, UserPO userPO) { logger.info("login name:" + userPO.getName() + ",pwd:" + userPO.getPasswd()); //一些必要的系統前置工做..... httpSession.setAttribute("user", userPO); return "success"; }
固然也能夠引入數據庫設計,劃分用戶角色來制定詳細的訪問策略。
最後繼承 Filter 接口攔截每次客戶端請求,來決定是否能獲取到對應的系統資源。
defaultPage 爲權限不足時默認跳轉的頁面,好比 Filter doFilter方法邏輯像下面。
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws Exception{ HttpServletRequest request = (HttpServletRequest) servletRequest; HttpSession session = request.getSession(false);
if ((session == null || session.getAttribute("user") == null) && !isFreeService(request.getRequestURI())) { request.setAttribute("SESSIONFILTER_MSG", "LOGIN_TIMEOUT"); request.getRequestDispatcher(defaultPage).forward(servletRequest, servletResponse);return; } filterChain.doFilter(servletRequest, servletResponse); }
到此,整個設計思路已敘述清楚,只需本身實現一個 Filter 便可,騷年是否是很簡單?
我的認爲其中的可擴展點還不少,作通用而且好用仍是有難度的,好比詳細的角色訪問策略,制定合理的設計模式。