如何實現(xiàn)一個權(quán)限管理系統(tǒng)?(附源碼)

2021-01-28    分類: 網(wǎng)站建設(shè)

系統(tǒng)安全一直是在系統(tǒng)開發(fā)中不可規(guī)避的問題,而權(quán)限控制又跟系統(tǒng)安全密不可分,大到用戶的訪問,小到一個頁面的按鈕,都有可能涉及到權(quán)限的控制。而renren-security便給我們提供了一套權(quán)限系統(tǒng)開發(fā)的解決方案。

renren-security是"人人社區(qū)"社區(qū)開源的輕量級權(quán)限管理系統(tǒng)。系統(tǒng)采用SprinBoot、Mybatis、Shiro框架進行開發(fā),極低門檻,拿來即用,支持分布式部署、Quartz分布式集群調(diào)度、部門管理、數(shù)據(jù)權(quán)限、云存儲等功能。

  • 靈活的權(quán)限控制,可控制到頁面或按鈕,滿足絕大部分的權(quán)限需求
  • 完善的部門管理及數(shù)據(jù)權(quán)限,通過注解實現(xiàn)數(shù)據(jù)權(quán)限的控制
  • 完善的XSS防范及腳本過濾,徹底杜絕XSS攻擊
  • 支持MySQL、Oracle、SQL Server、PostgreSQL等主流數(shù)據(jù)庫

    • 運行效果

      系統(tǒng)結(jié)構(gòu)的設(shè)計也比較清晰,由admin、api、common等幾個模塊組成,每個模塊實現(xiàn)的功能大體如下:

      common:公共模塊,以jar包的形式被其他模塊所依賴。實現(xiàn)了一些工具類和公共功能。包含時間處理、分頁、Sql過濾、Xss過濾和Redis切面定義、自定義異常處理等功能。

      admin:管理系統(tǒng)模塊,以war包形式獨立部署?;谇昂蠖朔蛛x的思想,主要用來用來開發(fā)后臺管理系統(tǒng)。包含用戶管理、角色管理、部門管理、菜單管理、定時任務(wù)、文件上傳、API校驗,同時采用Redis進行數(shù)據(jù)緩存,支持單機和集群的部署。

      api:API接口模塊,以war包形式獨立部署。模塊主要提供給前端UI調(diào)用的一些業(yè)務(wù)接口,實現(xiàn)了用戶注冊、登錄、接口權(quán)限認證和用戶信息獲取。同時整合了swagger2實現(xiàn)了API接口文檔,方便了接口的查詢和調(diào)試。


      系統(tǒng)架構(gòu)圖

      系統(tǒng)設(shè)計之初就特別注重安全性,基于Shiro在頁面和接口都實現(xiàn)了權(quán)限校驗。

      用戶登錄時對用戶的賬號密碼進行驗證,獲取用戶的信息和role權(quán)限,頁面顯示的時候會根據(jù)用戶擁有的權(quán)限顯示對應(yīng)的狀態(tài),接口請求的時候也會進行用戶權(quán)限的校驗,數(shù)據(jù)保存到數(shù)據(jù)庫時候還進行Sql和Xss的過濾,整個過程的核心思路是Shiro對用戶的認證和授權(quán)。具體流程如下圖:


      權(quán)限校驗整體思路

      Shiro的認證和授權(quán)

      實現(xiàn)Shiro的認證和授權(quán),需要自定義Realm繼承于AuthorizingRealm,同時重寫doGetAuthenticationInfo(認證)和doGetAuthorizationInfo(授權(quán))這兩個方法。這里對于系統(tǒng)與Shiro的整合就不再做多的說明。

      用戶登錄的時候,將用戶的賬號和密碼包裝成一個UsernamePasswordToken后,再調(diào)用login提交賬戶認證,shiro會自動調(diào)用我們重寫的doGetAuthenticationInfo方法。

      Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken(username, password);//提交認證subject.login(token);//Shiro進行認證@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken)authcToken; //獲取用戶信息 SysUserEntity user = new SysUserEntity(); user.setUsername(token.getUsername()); user = sysUserDao.selectOne(user); //賬號不存在 if(user == null) { throw new UnknownAccountException("賬號或密碼不正確"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName()); return info;}

      如果認證成功,那么在系統(tǒng)的任何地方通過SecurityUtils.getSubject()方法就可以獲取認證通過的信息。我們也可以借助它的這點特性,實現(xiàn)用戶的自動登錄。

      這里需要補充一點,系統(tǒng)把權(quán)限化成了一個個的標簽保存在數(shù)據(jù)庫中,用戶的權(quán)限中持有對應(yīng)的標簽則表示擁有對應(yīng)的操作權(quán)限。而對于Shiro的授權(quán),在doGetAuthorizationInfo中需要獲取用戶的所有權(quán)限列表,通過權(quán)限列表篩選出是否擁有操作權(quán)限。

      //Shiro進行授權(quán)@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //獲取認證時候添加到SimpleAuthenticationInfo中的實例 SysUserEntity user = (SysUserEntity)principals.getPrimaryPrincipal(); Long userId = user.getUserId(); //查詢用戶所有權(quán)限 Set<String> permsSet = new HashSet<String>(); List<String> permsList = sysUserDao.queryAllPerms(userId); for(String perms : permsList){ if(StringUtils.isBlank(perms)){ continue; } permsSet.addAll(Arrays.asList(perms.trim().split(","))); } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setStringPermissions(permsSet); return info;}

      Shiro的授權(quán)是被動的,只有被相應(yīng)的條件觸發(fā)才會進行用戶授權(quán),方式有以下幾種:

      1.作用于頁面。頁面里如果遇到<#if shiro.hasPermission("sys:del")>,Shiro會調(diào)用自定義Realm獲取權(quán)限信息,看"sys:del"是否在權(quán)限數(shù)據(jù)中存在,存在則授權(quán)通過,不存在則拒絕訪問,可應(yīng)用于對一些按鈕和標簽的特定開放。

      <#if shiro.hasPermission("sys:add")> <a @click="add">新增</a></#if><#if shiro.hasPermission("sys:del")> <a @click="del">刪除</a></#if>

      2.通過注解的方式作用于接口。在controller中,方法如果加了@RequiresPermissions("sys:del")注解,Shiro同樣會調(diào)用自定義Realm獲取權(quán)限信息,看"sys:del"是否在權(quán)限數(shù)據(jù)中存在,存在則授權(quán)通過,不存在則拒絕訪問,從而實現(xiàn)對接口的權(quán)限校驗。

      @RequestMapping("/delete")@RequiresPermissions("sys:del")public R delete(long deptId){ //判斷是否有子部門 List<Long> deptList = sysDeptService.queryDetpIdList(deptId); if(deptList.size() > 0){ return R.error("請先刪除子部門"); } sysDeptService.deleteById(deptId); return R.ok();}

      到此,基本上便實現(xiàn)了Shiro在頁面和接口的權(quán)限控制。當然,Shiro更多是作用于表現(xiàn)層的一個控制,而出于系統(tǒng)安全考慮也應(yīng)該增加對數(shù)據(jù)的校驗。因此在數(shù)據(jù)層面,則可通過Sql過濾和Xss過濾的方式實現(xiàn)過濾。項目中已經(jīng)為其封裝成工具,原理都是正則匹配和字符串替換,感興趣的伙伴可以直接到項目里查看,這里就不再累述了。

      系統(tǒng)除了實現(xiàn)權(quán)限控制外,也實現(xiàn)了很多后臺管理系統(tǒng)開發(fā)中常用到的一些功能,像Quartz分布式集群調(diào)度、多數(shù)據(jù)源動態(tài)切換以及集群部署下Session管理,感興趣的伙伴也可以查看源碼。

      項目地

      網(wǎng)頁名稱:如何實現(xiàn)一個權(quán)限管理系統(tǒng)?(附源碼)
      鏈接分享:http://muchs.cn/news37/97787.html

      成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗、App開發(fā)、網(wǎng)站收錄、搜索引擎優(yōu)化靜態(tài)網(wǎng)站、企業(yè)建站

      廣告

      聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

      小程序開發(fā)