首页 > 解决方案 > 使用 vuejs 和 laravel 的权限和角色

问题描述

这是我使用 CASL 的当前设置。目前它似乎没有读取我要导入到 ability.js 文件中的规则数组。如果您也想查看,我还将功能插件导入到 main.js 文件中

这是ability.js文件

import { Ability } from '@casl/ability'

export const ability = new Ability()

export const abilityPlugin = (store) => {
  ability.update(store.state.rules)

  return store.subscribe((mutation) => {
    switch (mutation.type) {
    case 'createSession':
      ability.update(mutation.payload.rules)
      break
    case 'destroySession':
      ability.update([{ actions: 'read', subject: 'all' }])
      break
    }
  })
}

这是调用规则列表的商店

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import storage from './utils/storage'
import { abilityPlugin, ability as appAbility } from './utils/ability'

export const ability = appAbility
Vue.use(Vuex)
axios.defaults.baseURL = 'http://todo-laravel.test/api'

export default new Vuex.Store({
  plugins: [
    storage({
      storedKeys: ['rules'],
      destroyOn: ['destroySession']
    }),
    abilityPlugin
  ],
  state: {
    rules: '',
    token: localStorage.getItem('access_token') || null,
  },
  mutations: {
    createSession(state, role) {
      state.rules = role[0]
    },
    destroySession(state) {
      state.rules = ''
    },
    retrieveToken(state, token) {
      state.token = token
    },
    destroyToken(state) {
      state.token = null
    },
  },
  actions: {
    destroyToken(context) {
      axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token

      if (context.getters.loggedIn) {
        return new Promise((resolve, reject) => {
          axios.post('/logout')
          .then(response => {
            localStorage.removeItem('access_token')
            context.commit('destroyToken')
            context.commit('destroySession')
            resolve(response)
          })
          .catch(error => {
            localStorage.removeItem('access_token')
            context.commit('destroyToken')
            reject(error)
          })
        })
      }
    },
    retrieveToken({ commit, dispatch }, credentials) {

      return new Promise((resolve, reject) => {
          axios.post('/login', {
              username: credentials.username,
              password: credentials.password,
          })
          .then(response => {
              const token = response.data.access_token

              localStorage.setItem('access_token', token)
              commit('retrieveToken', token)
              dispatch('retrieveRules')
              resolve(response)
          })
          .catch(error => {
              console.log(error)
              reject(error)
          })
      })
    },
    retrieveRules(context) {
      axios.defaults.headers.common['Authorization'] = 'Bearer ' + context.state.token

      return new Promise((resolve, reject) => {
          axios.get('/rules')
          .then(response => {
              console.log(response.data)
              context.commit('createSession', response.data)
              resolve(response)
          })
          .catch(error => {
              console.log(error.response.data)
              reject(error)
          })
      })
    },

这是保存在存储中的规则数组

[{id: 1, role_id: 3, action: "Manage", subject: "All"}]

标签: laravelvue.jsvue-componentlaravel-passportcasl

解决方案


您需要定义可以在该主题上执行的 subjets 和操作(例如,用户可以阅读帖子翻译为 -> 主题:“帖子”,操作:“阅读”)。当您这样做时,您可以在 API 端为经过身份验证的用户创建一个路由(或将其作为身份验证响应的一部分返回),该路由返回用户特定的操作。例如:

如果用户是管理员,他可以做任何事情,所以响应应该是:

{
  "rules": [
    { "action": "manage", "subject": "all" } 
  ]
}

如果用户是团队成员,那么他有一些受限的权限(假设他只能读取设置):

{
  "rules": [
    { "action": "read", "subject": "Settings" } 
  ]
}

在用户界面方面:

如果你不使用 Vuex:

// main.js
import { abilitiesPlugin } from '@casl/vue'
import Vue from 'vue'

Vue.use(abilitiesPlugin);

// inside LoginComponent
{
  methods: {
    login() {
      return this.http.post(...)
        .then(respose => this.$ability.update(response.data.rules)
    }
  }
}

如果你使用 Vuex:

// main.js
import { abilitiesPlugin } from '@casl/vue'
import Vue from 'vue'
import ability from './services/ability';

Vue.use(abilitiesPlugin, ability);


// services/ability.js
import { Ability } from '@casl/ability';

export default new Ability()


// store.js
import ....
import ability from './services/ability'

const updateAbilities = (store) => {
  ability.update(store.state.rules) // take rules from your state structure

  return store.subscribe((mutation) => {
    switch (mutation.type) {
    case 'login':
      ability.update(mutation.payload.rules)
      break
    case 'logout':
      ability.update([{ actions: 'read', subject: 'all' }]) // read only mode
      // or `ability.update([])` to remove all permissions
      break
    }
  })
}

export default new Vuex.Store({
  plugins: [
    updateAbilities
  ],
  // ... your store declaration
})

您可以查看https://github.com/stalniy/casl-vue-api-example这是 Vue、CASL 和 Rails 集成的示例,以查看一些详细信息

更新

稍后在所有组件中,只需使用$can函数或<can>组件来检查权限。查看CASL Vue 文档了解详细信息


推荐阅读