<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          zhcc基于 vue+ ssm + shiro 的權(quán)限框架

          聯(lián)合創(chuàng)作 · 2023-09-30 08:53

          zhcc

          基于vue(element ui) + ssm + shiro 的權(quán)限框架

          隨著前后端分離項目的熱潮,前端各大框架的,前后端溝通部分也成了問題,之前服務(wù)端渲染的頁面生成到前端來,現(xiàn)在前后端可能是兩個服務(wù)器,一些技術(shù)的遷移,本框架的權(quán)限部分的設(shè)計思想,借鑒了前端大牛的想法,也有傳統(tǒng)后端的設(shè)計方案,拋磚引玉,做個橋梁,實現(xiàn)前后端分離的權(quán)限的設(shè)計,代碼僅供參考,思路僅供參考,相信優(yōu)秀的你寫自己的代碼,用自己的思想會更為貼切,方便。 最終即具有統(tǒng)一響應(yīng)結(jié)構(gòu)、 前后臺數(shù)據(jù)流轉(zhuǎn)機制(HTTP消息與Java對象的互相轉(zhuǎn)化機制)、統(tǒng)一的異常處理機制、參數(shù)驗證機制、Cors跨域請求機制以及鑒權(quán)機制。

          前端設(shè)計:采用 Vue 的 element ui ,對于前端設(shè)計者來說,應(yīng)該很好理解源碼。

          后端設(shè)計:shiro + ssm + redis 存儲 jwt

          交互方式:前端存儲jwt,在訪問后端時攜帶,這也是唯一交互驗證方式。

          前期工作:設(shè)計符合需求的vue模板,路由,資源,角色,用戶其中對應(yīng)關(guān)系也可從數(shù)據(jù)表中體現(xiàn)出來。

          設(shè)計思路

          基本想法就是,用到Vuex 和 Vue Router 前者用來做狀態(tài)控制,后者綁定路由,這樣權(quán)限可以直接對應(yīng)到組件上,某個用于只能訪問某個組件,而不用將每個組件都加上權(quán)限控制,重要的是還有單點登錄。 所以拋磚引玉,寫一個通用框架,(至少是通用想法)具體可以模塊化來可插拔就ok 了。 非動態(tài)路由的問題是只能在拿到權(quán)限之后初始化Vue實例,因此必須把登陸頁從SPA中剝離出來做成一個獨立的頁面,用戶登錄/退出操作需要在兩個url之間跳轉(zhuǎn),體驗略差。

          另一種做法是直接用所有路由實例化應(yīng)用,當(dāng)用戶登錄拿到權(quán)限后再通過元素操作隱藏越權(quán)菜單,這時用戶還可以手動輸入地址訪問越權(quán)頁面,因此還需要給路由加beforeEach鉤子來限制路由訪問,路由鉤子本身會增加一定的性能壓力,而且實例化即注冊所有路由也會使前端加載冗余的路由組件。 本系統(tǒng)采用的在初始路由注冊首頁和登錄頁,并在拿到token后得到權(quán)限,然后在實例化Vue實例。路由代碼如下:

          const router = new Router({
            routes: [
              {
                path: '/login',
                name: "login",
                component: LoginView,
                meta: { requiresAuth: false }
              },{
                path: '/index',
                redirect: '/',
                meta: { requiresAuth: true }
              }
            ]
          });
          generateIndexRouter();
          
          // 驗證token,存在才跳轉(zhuǎn)
          router.beforeEach((to, from, next) => {
            let token = sessionStorage.getItem('token')
            if(to.path === '/') {
              if(!token) {
                next({
          				path: '/login',
          				query: { redirect: to.fullPath }
                })
                return
              }
            }
          
          	if(to.meta.requiresAuth) {
          		if(token) {
          			next()
          		} else {
          			next({
          				path: '/login',
          				query: { redirect: to.fullPath }
          			})
          		}
          	} else {
          		next()
          	}
          });
          
          router.afterEach((to, from) => {
            // 設(shè)置面包屑
            let breadCrumbItems = []
            let homePageCrumb = {
              title: '首頁',
              to: '/'
            }
            breadCrumbItems.push(homePageCrumb)
            if(to.meta.nameFullPath) {
              let fullPathSplit = to.meta.nameFullPath.split('/')
              fullPathSplit.forEach(( item, index ) => {
                let routerBreadCrumb = {
                  title: item,
                  to: (index == fullPathSplit.length - 1 ? to.path : '')
                }
                breadCrumbItems.push(routerBreadCrumb)
              });
            }
            // 更新到state
            router.app.$store.dispatch('setBreadcurmbItems', breadCrumbItems)
          })
          
          // 生成首頁路由
          function generateIndexRouter() {
            if (!sessionStorage.routers) {
              return
            }
            let indexRouter = {
              path: "/",
              name: "/",
              component: resolve => require(['@/views/home/index'], resolve),
              children: [
                ...generateChildRouters()
              ]
            }
            router.addRoutes([indexRouter])
          }
          
          // 生成嵌套路由(子路由)
          function generateChildRouters() {
            let routers = JSON.parse(sessionStorage.routers)
            let childRouters = []
            for(let router of routers) {
              if(router.code != null) {
                let routerProps = JSON.parse(router.properties)
                let childRouter = {
                  path: router.url,
                  name: router.code,
                  component: resolve => require(['@/views/' + router.code + '/index'], resolve),
                  meta: { routerId: router.id, requiresAuth: routerProps.meta.requiresAuth, nameFullPath: routerProps.nameFullPath }
                }
                childRouters.push(childRouter)
              }
            }
            return childRouters
          }
          
          export default router;

          前后端數(shù)據(jù)格式約定

          既然是restful風(fēng)格,必然有通用返回狀態(tài)的類,遵循網(wǎng)上開源原則,一類繼承hashmap這樣達到可以返回任意的數(shù)據(jù),通用的數(shù)據(jù)就是code.msg.data這些,如果有分頁會另外加分頁,還有一種是,data.msg.state(code).token + 分頁類型的數(shù)據(jù)如:

          "data": {
              "list": null,
              "pagebar": {
                "page": 1,
                "total": 2,
                "limit": 10
              }
            },
           "msg": "error",
            "state": 0,
            "is_redirect": true,
            "redirect_url": "http://qq.com",
            "token": null

          本項目考慮到后期的擴展性,用到了第一類,其中實現(xiàn)了常用的失敗和成功的狀態(tài)碼及其響應(yīng),類名設(shè)計為Result,位于zhcc-common下面,一般性地是封裝到ResponseEntity中返回。

          前后端數(shù)據(jù)接口約定

          分別對應(yīng)http協(xié)議的get/put/post/delete方法,后端權(quán)限是:read/:update/:create/:delete

          case "get":
              permissionString += ":read";
              break;
          case "put":
              permissionString += ":update";
              break;
          case "post":
              permissionString += ":create";
              break;
          case "delete":
              permissionString += ":delete";

          驗證部分

          用的是com.baidu.unbiz.fluentvalidator.ValidationError 而不是hibernateValidator 減輕服務(wù)端編程等的壓力。直接在controller里面驗證,最后封裝到Result的fail方法里面返回。

          權(quán)限的設(shè)計

          權(quán)限的控制主要分為4大類,主要是基于RBAC原理。 路由,資源,角色,用戶 路由級別和組件級別可控制

          過程設(shè)計

          1.權(quán)限設(shè)計 2.異常設(shè)計 3.字典和其他接口設(shè)計 4.前后的通訊設(shè)計==

          瀏覽 26
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          編輯 分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          編輯 分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美成人片网站 | 欧美三级在线观看网页 | 中文无码第一页 | 日女人毛片 | 久久久久无码精品人妻 |