権限制御に vue、vue-router、vuex、addRoutes を使用する方法

php中世界最好的语言
リリース: 2018-06-01 11:45:02
オリジナル
1465 人が閲覧しました

今回は、vue、vue-router、vuex、addRoutes を使用して権限を制御する方法について説明します。注意点と具体的なケースについて説明します。

vuex、vue-router、vuex に基づく権限制御チュートリアル。完全なコード アドレスは

https://github.com/linrunzheng/vue-permission-control にあります

次に、シミュレーションしてみましょう一般ユーザーがウェブサイトを開くプロセス全体を段階的に説明します。

まず、ローカルサービスlocalhost:8080を開くことから始めます。開いた後、ログインページに入ることがわかっていますが、判断の根拠は何ですか。

まずトークンです。

ログインしていないユーザーはトークンを取得できません。ログインしているキャラクターの場合、トークンはローカルまたはseesionStorageに保存されます。そのため、ログインするかどうかは、現在のトークン。

トークンにアクセスして操作を容易にするために、vuexと組み合わせて

/* state.js */
export default {
 get UserToken() {
 return localStorage.getItem('token')
 },
 set UserToken(value) {
 localStorage.setItem('token', value)
 }
}
/* mutation.js */
export default {
 LOGIN_IN(state, token) {
 state.UserToken = token
 },
 LOGIN_OUT(state) {
 state.UserToken = ''
 }
}
ログイン後にコピー

傍受の判断

許可が必要なページに入るトークンがない場合: ログインにリダイレクトしますpage

私たちのルートは「 」と404を含めて動的にマウントされているため、ルートが一致しない場合もlogin

router.beforeEach((to, from, next) => {
 if (!store.state.UserToken) {
 if (
 to.matched.length > 0 &&
 !to.matched.some(record => record.meta.requiresAuth)
 ) {
 next()
 } else {
 next({ path: '/login' })
 }
 } 
})
ログイン後にコピー
にリダイレクトされます。この時点で、ユーザーはlocalhost:8080を開き、デフォルトの一致は '' パスであり、現時点ではルートをマウントしておらず、トークンもないため、ログインするようになりました。

ユーザー名とパスワードを入力すると、ストアを介してトークンを設定するための *commit('LOGIN_IN')* が実行されます。

しかし、ルートはまだありません。現時点では、ログイン ルートしかありません

/* 初始路由 */
export default new Router({
 routes: [
 {
 path: '/login',
 component: Login
 }
 ]
})
/* 准备动态添加的路由 */
export const DynamicRoutes = [
 {
 path: '',
 component: Layout,
 name: 'container',
 redirect: 'home',
 meta: {
 requiresAuth: true,
 name: '首页'
 },
 children: [
 {
 path: 'home',
 component: Home,
 name: 'home',
 meta: {
  name: '首页'
 }
 }
 ]
 },
 {
 path: '/403',
 component: Forbidden
 },
 {
 path: '*',
 component: NotFound
 }
]
ログイン後にコピー
現在のユーザーのトークンに基づいて権限を取得するには、バックグラウンドに移動する必要があります。

権限には非常に多くのロジックがあるため、権限を処理するための権限モジュールが vuex に追加されました。

既存のルートリストがあるかどうかを判断するには、vuexのpermissionモジュールに状態permissionListを保存する必要があります。permissionListがnullでない場合、つまりルートがすでに存在する場合です。存在するので、私たちは働く必要があります。

router.beforeEach((to, from, next) => {
 if (!store.state.UserToken) {
 ...
 } else {
 /* 现在有token了 */
 if (!store.state.permission.permissionList) {
 /* 如果没有permissionList,真正的工作开始了 */
 store.dispatch('permission/FETCH_PERMISSION').then(() => {
 next({ path: to.path })
 })
 } else {
 if (to.path !== '/login') {
 next()
 } else {
 next(from.fullPath)
 }
 }
 }
})
ログイン後にコピー
store.dispatch('permission/FETCH_PERMISSION') が何をするのか見てみましょう

actions: {
 async FETCH_PERMISSION({ commit, state }) {
 /* 获取后台给的权限数组 */
 let permissionList = await fetchPermission()
 /* 根据后台权限跟我们定义好的权限对比,筛选出对应的路由并加入到path=''的children */
 let routes = recursionRouter(permissionList, dynamicRouter)
 let MainContainer = DynamicRoutes.find(v => v.path === '')
 let children = MainContainer.children
 children.push(...routes)
 /* 生成左侧导航菜单 */
 commit('SET_MENU', children)
 setDefaultRoute([MainContainer])
 /* 初始路由 */
 let initialRoutes = router.options.routes
 /* 动态添加路由 */
 router.addRoutes(DynamicRoutes)
 /* 完整的路由表 */
 commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes])
 }
}
ログイン後にコピー
まず、await fetchPermission() はバックグラウンドで与えられた権限配列を取得します。フォーマットはおおよそ次のとおりです

{
 "code": 0,
 "message": "获取权限成功",
 "data": [
 {
 "name": "订单管理",
 "children": [
 {
  "name": "订单列表"
 },
 {
  "name": "生产管理",
  "children": [
  {
  "name": "生产列表"
  }  
  ]
 },
 {
  "name": "退货管理"
 }
 ]
 }
 ]
}
ログイン後にコピー
次に、ベースになります。作成したルーティング配列に対して、比較およびフィルタリングして、必要なルートを取得します

/* 这里是我们写好的需要权限判断的路由 */
const dynamicRoutes = [
 {
 path: '/order',
 component: Order,
 name: 'order-manage',
 meta: {
 name: '订单管理'
 },
 children: [
 {
 path: 'list',
 name: 'order-list',
 component: OrderList,
 meta: {
  name: '订单列表'
 }
 },
 {
 path: 'product',
 name: 'product-manage',
 component: ProductManage,
 meta: {
  name: '生产管理'
 },
 children: [
  {
  path: 'list',
  name: 'product-list',
  component: ProductionList,
  meta: {
  name: '生产列表'
  }
  },
  {
  path: 'review',
  name: 'review-manage',
  component: ReviewManage,
  meta: {
  name: '审核管理'
  }
  }
 ]
 },
 {
 path: 'returnGoods',
 name: 'return-goods',
 component: ReturnGoods,
 meta: {
  name: '退货管理'
 }
 }
 ]
 }
]
export default dynamicRoutes
ログイン後にコピー
比較のために、

再帰関数を作成し、この関数に基づいて結果を取得します。 want

/**
 *
 * @param {Array} userRouter 后台返回的用户权限json
 * @param {Array} allRouter 前端配置好的所有动态路由的集合
 * @return {Array} realRoutes 过滤后的路由
 */
export function recursionRouter(userRouter = [], allRouter = []) {
 var realRoutes = []
 allRouter.forEach((v, i) => {
 userRouter.forEach((item, index) => {
 if (item.name === v.meta.name) {
 if (item.children && item.children.length > 0) {
  v.children = recursionRouter(item.children, v.children)
 }
 realRoutes.push(v)
 }
 })
 })
 return realRoutes
}
ログイン後にコピー
get 配列をフィルタリングした後、パス「

{
 path: '',
 component: Layout,
 name: 'container',
 redirect: 'home',
 meta: {
 requiresAuth: true,
 name: '首页'
 },
 children: [
 {
 path: 'home',
 component: Home,
 name: 'home',
 meta: {
  name: '首页'
 }
 },
 <!-- 将上面得到的东西加入到这里 -->
 ...
 ]
 }
ログイン後にコピー
」を持つ子に追加します。現時点では、パス「」を持つ子は左側のナビゲーション メニューであり、後で使用するために状態のサイドバーメニューに保存されます。子に追加した後、DynamicRoutes をルートに追加できます。

/* 动态添加路由 */
router.addRoutes(DynamicRoutes)
 /* 初始路由 */
let initialRoutes = router.options.routes
/* 合并起来,就是完整的路由了 */
commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes])
ログイン後にコピー
ルートが追加された後、つまりアクション操作が完了したら、action.then で next({ path: to.path }) を呼び出してルートに入ることができます。ここで、パラメータが next に渡されることに注意してください。 , これはルーティング情報を入力するページですが、次のパラメータを渡した後は、現在入力しているルートが廃止され、同じルートですが、主にこれが入力されます。 addRoutes が確実に有効になるようにします。

ルーティングを入力したら、左側のメニューの生成を開始する必要があります。これは以前にsidebarMenuに保存しましたが、再帰ルーティングの場合は、要素のナビゲーションメニューを使用してメニューを再帰的に生成するだけです。 、それを自分でカプセル化する必要があります。ここでのコアはコンポーネントの名前です。コンポーネント内に子がある場合は、再度自分自身を使用してツリー構造全体のルーティングをたどります。

<template>
 <p class="menu-container">
 <template v-for="v in menuList">
 <el-submenu :index="v.name" v-if="v.children&&v.children.length>0" :key="v.name">
 <template slot="title">
  <i class="iconfont icon-home"></i>
  <span>{{v.meta.name}}</span>
 </template>
 <el-menu-item-group>
  <my-nav :menuList="v.children"></my-nav>
 </el-menu-item-group>
 </el-submenu>
 <el-menu-item :key="v.name" :index="v.name" @click="gotoRoute(v.name)" v-else>
 <i class="iconfont icon-home"></i>
 <span slot="title">{{v.meta.name}}</span>
 </el-menu-item>
 </template>
 </p>
</template>
<script>
export default {
 name: 'my-nav',
 props: {
 menuList: {
 type: Array,
 default: function() {
 return []
 }
 }
 },
 methods: {
 gotoRoute(name) {
 this.$router.push({ name })
 }
 }
}
</script>
ログイン後にコピー
ページを更新した後、router.beforeEach の判断に従って、トークンはあるが許可リストが存在しないと、ルートを取得するためのアクションが再トリガーされますので、心配する必要はありません。ただし、ナビゲーション メニューのアクティブ効果は消えます。ただし、el-menu-item のキーをルートの名前に設定しているため、更新後の afterEach で現在のルートの名前を el-menudefault-active に割り当てるだけで済みます。同様に、

ブレッドクラム ナビゲーションは、afterEach ステージで一致するすべてのルートを取得することで実現できます。

if (!store.state.permission.permissionList) {
 store.dispatch('permission/FETCH_PERMISSION').then(() => {
 next({ path: to.path })
 })
} 
...
router.afterEach((to, from, next) => {
 var routerList = to.matched
 store.commit('setCrumbList', routerList)
 store.commit('permission/SET_CURRENT_MENU', to.name)
})
ログイン後にコピー

退出登陆后,需要刷新页面,因为我们是通过addRoutes添加的,router没有deleteRoutes这个api,所以清除token,清除permissionList等信息,刷新页面是最保险的。

最后还有一点,每次请求得带上token, 可以对axios封装一下来处理

var instance = axios.create({
 timeout: 30000,
 baseURL
})
// 添加请求拦截器
instance.interceptors.request.use(
 function(config) {
 // 请求头添加token
 if (store.state.UserToken) {
 config.headers.Authorization = store.state.UserToken
 }
 return config
 },
 function(error) {
 return Promise.reject(error)
 }
)
/* axios请求二次封装 */
instance.get = function(url, data, options) {
 return new Promise((resolve, reject) => {
 axios
 .get(url, data, options)
 .then(
 res => {
  var response = res.data
  if (response.code === 0) {
  resolve(response.data)
  } else {
  Message.warning(response.message)
  /* reject(response.message) */
  }
 },
 error => {
  if (error.response.status === 401) {
  Message.warning({
  message: '登陆超时,请重新登录'
  })
  store.commit('LOGIN_OUT')
  window.location.reload()
  } else {
  Message.error({
  message: '系统异常'
  })
  }
  reject(error)
 }
 )
 .catch(e => {
 console.log(e)
 })
 })
}
export default instance
ログイン後にコピー

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

使用JS判断字符串中包含内容方法总结

Angular+RouterLink做出不同的花式跳转

以上が権限制御に vue、vue-router、vuex、addRoutes を使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!