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

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

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

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

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

    • 運(yùn)行效果

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

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

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

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


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

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

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


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

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

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

      用戶登錄的時(shí)候,將用戶的賬號(hào)和密碼包裝成一個(gè)UsernamePasswordToken后,再調(diào)用login提交賬戶認(rèn)證,shiro會(huì)自動(dòng)調(diào)用我們重寫(xiě)的doGetAuthenticationInfo方法。

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

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

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

      //Shiro進(jìn)行授權(quán)@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //獲取認(rèn)證時(shí)候添加到SimpleAuthenticationInfo中的實(shí)例 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)是被動(dòng)的,只有被相應(yīng)的條件觸發(fā)才會(huì)進(jìn)行用戶授權(quán),方式有以下幾種:

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

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

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

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

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

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

      項(xiàng)目地

      網(wǎng)頁(yè)名稱(chēng):如何實(shí)現(xiàn)一個(gè)權(quán)限管理系統(tǒng)?(附源碼)
      鏈接分享:http://www.bm7419.com/news37/97787.html

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

      廣告

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

      小程序開(kāi)發(fā)