Browse Source

refactor(keycloak): adjust keycloak apis

keycloak api -> server api, keycloak update
Casper Dai 2 years ago
parent
commit
49109ac9ea

+ 0 - 3
.env

@@ -20,9 +20,6 @@ VUE_APP_NAME = '浪潮屏媒安播云平台'
 # gateway
 VUE_APP_GATEWAY = ''
 
-# backend client
-VUE_APP_BACKEND_CLIENT = 'backend-api'
-
 # base api
 VUE_APP_BASE_API = '/prod-api'
 

+ 167 - 36
src/api/user.js

@@ -9,16 +9,14 @@ import {
   messageSend
 } from './base'
 
-// 公众号二维码
-export function getTicket (id) {
+export function getWechatQr (id) {
   return request({
     url: `keycloak/query/ticket/${id}`,
     method: 'GET'
   })
 }
 
-// 小程序二维码
-export function getQrcode (data) {
+export function getAppletQr (data) {
   return request({
     url: `wxapplet/qrcode`,
     method: 'GET',
@@ -28,7 +26,6 @@ export function getQrcode (data) {
 
 export function userinfo (silence) {
   const config = {
-    // url: `${baseUrl}/realms/${realm}/account`,
     url: `/users/${store.getters.userId}`,
     method: 'GET'
   }
@@ -40,55 +37,116 @@ export function userinfo (silence) {
 }
 
 export function addUserAccount (data) {
+  if (store.getters.canManageUsers) {
+    return add({
+      url: '/users',
+      method: 'POST',
+      data: {
+        ...data,
+        credentials: [{ type: 'password', value: process.env.VUE_APP_USER_PASSWORD, temporary: true }]
+      }
+    }, keycloakRequest)
+  }
   return add({
-    url: `/users`,
+    url: '/admin/users',
     method: 'POST',
     data: {
       ...data,
       credentials: [{ type: 'password', value: process.env.VUE_APP_USER_PASSWORD, temporary: true }]
     }
-  }, keycloakRequest)
+  })
 }
 
-export function updateUser (id, data, message) {
+export function updateUser (data, message) {
+  if (store.getters.canManageUsers) {
+    return update({
+      url: `/users/${store.getters.userId}`,
+      method: 'PUT',
+      data
+    }, message, keycloakRequest)
+  }
   return update({
-    url: `/users/${id}`,
+    url: '/keycloak/users/attribute',
     method: 'PUT',
     data
-  }, message, keycloakRequest)
+  }, message)
+}
+
+export function toggleUser (id, enabled) {
+  if (store.getters.canManageUsers) {
+    return update({
+      url: `/users/${id}`,
+      method: 'PUT',
+      data: { enabled }
+    }, enabled ? '启用' : '停用', keycloakRequest)
+  }
+  return update({
+    url: `/admin/users/${id}`,
+    method: 'PUT',
+    data: { enabled }
+  }, enabled ? '启用' : '停用')
 }
 
 export function deleteUser ({ id }) {
-  return keycloakRequest({
-    url: `/users/${id}`,
+  if (store.getters.canManageUsers) {
+    return keycloakRequest({
+      url: `/users/${id}`,
+      method: 'DELETE'
+    })
+  }
+  return request({
+    url: `/admin/users/${id}`,
     method: 'DELETE'
   })
 }
 
 export function getUserCredentials ({ id }) {
-  return keycloakRequest({
-    url: `/users/${id}/credentials`,
+  if (store.getters.canManageUsers) {
+    return keycloakRequest({
+      url: `/users/${id}/credentials`,
+      method: 'GET'
+    })
+  }
+  return request({
+    url: `/admin/users/${id}/credentials`,
     method: 'GET'
-  })
+  }).then(({ data }) => data)
 }
 
 export function deleteUserCredentials (userId, credentialId) {
-  return send({
-    url: `/users/${userId}/credentials/${credentialId}`,
+  if (store.getters.canManageUsers) {
+    return messageSend({
+      url: `/users/${userId}/credentials/${credentialId}`,
+      method: 'DELETE'
+    }, '重置', keycloakRequest)
+  }
+  return messageSend({
+    url: `/admin/users/${userId}/credentials/${credentialId}`,
     method: 'DELETE'
-  }, keycloakRequest)
+  }, '重置')
 }
 
 export function resetPassword ({ id }) {
+  if (store.getters.canManageUsers) {
+    return messageSend({
+      url: `/users/${id}/reset-password`,
+      method: 'PUT',
+      data: {
+        type: 'password',
+        value: process.env.VUE_APP_USER_PASSWORD,
+        temporary: true
+      }
+    }, '重置', keycloakRequest)
+  }
   return messageSend({
-    url: `/users/${id}/reset-password`,
+    url: `/admin/users/${id}/resetPassword`,
     method: 'PUT',
     data: {
       type: 'password',
       value: process.env.VUE_APP_USER_PASSWORD,
       temporary: true
     }
-  }, '重置', keycloakRequest)
+  }, '重置')
 }
 
 export function resetPasswordByUser (newPassword) {
@@ -175,8 +233,20 @@ export function getTenantGroups () {
 }
 
 export function addTenant ({ name, remark }) {
+  if (store.getters.canManageUsers) {
+    return add({
+      url: '/groups',
+      method: 'POST',
+      data: {
+        name,
+        attributes: {
+          remark: [remark]
+        }
+      }
+    }, keycloakRequest)
+  }
   return add({
-    url: '/groups',
+    url: '/super/admin/tenant',
     method: 'POST',
     data: {
       name,
@@ -184,7 +254,17 @@ export function addTenant ({ name, remark }) {
         remark: [remark]
       }
     }
-  }, keycloakRequest)
+  })
+}
+
+export function deleteTenant ({ id }) {
+  if (store.getters.canManageUsers) {
+    return deleteGroup({ id })
+  }
+  return request({
+    url: `/super/admin/tenant/${id}`,
+    method: 'DELETE'
+  })
 }
 
 async function getGroups () {
@@ -199,19 +279,41 @@ async function getGroups () {
 }
 
 export function addSubGroup ({ id }, { name, remark }) {
+  if (store.getters.canManageUsers) {
+    return add({
+      url: `/groups/${id}/children`,
+      method: 'POST',
+      data: {
+        name,
+        attributes: { remark: [remark] }
+      }
+    }, keycloakRequest)
+  }
   return add({
-    url: `/groups/${id}/children`,
+    url: `/admin/group/${id}/children`,
     method: 'POST',
     data: {
       name,
       attributes: { remark: [remark] }
     }
-  }, keycloakRequest)
+  })
 }
 
 export function updateGroup ({ id, name, remark }) {
+  if (store.getters.canManageUsers) {
+    return update({
+      url: `/groups/${id}`,
+      method: 'PUT',
+      data: {
+        name,
+        attributes: {
+          remark: [remark]
+        }
+      }
+    }, null, keycloakRequest)
+  }
   return update({
-    url: `/groups/${id}`,
+    url: `/admin/group/${id}`,
     method: 'PUT',
     data: {
       name,
@@ -219,12 +321,18 @@ export function updateGroup ({ id, name, remark }) {
         remark: [remark]
       }
     }
-  }, null, keycloakRequest)
+  })
 }
 
 export function deleteGroup ({ id }) {
-  return keycloakRequest({
-    url: `/groups/${id}`,
+  if (store.getters.canManageUsers) {
+    return keycloakRequest({
+      url: `/groups/${id}`,
+      method: 'DELETE'
+    })
+  }
+  return request({
+    url: `/admin/group/${id}`,
     method: 'DELETE'
   })
 }
@@ -260,6 +368,16 @@ export function getUserGroups (id, briefRepresentation = true) {
   }).then(data => data.sort((a, b) => a.path.length - b.path.length))
 }
 
+export function moveUserGroup (userId, from, to) {
+  if (store.getters.canManageUsers) {
+    return moveUserGroupByKeycloak(userId, from, to)
+  }
+  return request({
+    url: `/admin/users/${userId}/groups/${to.id}`,
+    method: 'PUT'
+  })
+}
+
 function addUserToGroup (userId, groupId) {
   return keycloakRequest({
     url: `/users/${userId}/groups/${groupId}`,
@@ -274,7 +392,7 @@ function removeUserFromGroup (userId, groupId) {
   })
 }
 
-export async function moveUserGroup (userId, from, to) {
+async function moveUserGroupByKeycloak (userId, from, to) {
   const fromGroups = getGroupList(from)
   const toGroups = getGroupList(to)
   let fromLast = fromGroups.length - 1
@@ -347,9 +465,6 @@ export async function updateUserRoles (userId, available, fromKeys, toKeys) {
       delRoles.push(available.find(role => role.id === id))
     }
   })
-  if (delRoles.length) {
-    await removeUserRoles(userId, delRoles)
-  }
   const addRoles = []
   const fromSet = new Set(fromKeys)
   toKeys.forEach(id => {
@@ -357,9 +472,24 @@ export async function updateUserRoles (userId, available, fromKeys, toKeys) {
       addRoles.push(available.find(role => role.id === id))
     }
   })
-  if (addRoles.length) {
-    await addUserRoles(userId, addRoles)
+  if (store.getters.canManageUsers) {
+    if (delRoles.length) {
+      await removeUserRoles(userId, delRoles)
+    }
+    if (addRoles.length) {
+      await addUserRoles(userId, addRoles)
+    }
+    return Promise.resolve()
   }
+  return request({
+    url: '/admin/users/role/configure',
+    method: 'PUT',
+    data: {
+      userId,
+      addRoleList: addRoles,
+      removeRoleList: delRoles
+    }
+  })
 }
 
 function removeUserRoles (userId, roles) {
@@ -377,7 +507,8 @@ function addUserRoles (userId, roles) {
     data: roles
   })
 }
-export function authcodeSend (data) {
+
+export function sendVerificationCode (data) {
   return request({
     url: `/authcode/send`,
     method: 'POST',
@@ -385,7 +516,7 @@ export function authcodeSend (data) {
   })
 }
 
-export function authcodeCheck (data) {
+export function checkVerificationCode (data) {
   return request({
     url: `/authcode/check`,
     method: 'POST',

+ 0 - 57
src/components/dialog/EventTargetDialog/index.vue

@@ -1,57 +0,0 @@
-<template>
-  <confirm-dialog
-    ref="confirmDialg"
-    size="lg fixed"
-    v-bind="$attrs"
-    v-on="listeners"
-  >
-    <template #default>
-      <event-target-picker
-        ref="eventTargetPicker"
-        class="l-flex__fill"
-        :ratio="ratio"
-      />
-    </template>
-  </confirm-dialog>
-</template>
-
-<script>
-export default {
-  name: 'EventTargetDialog',
-  props: {
-    ratio: {
-      type: String,
-      default: ''
-    }
-  },
-  data () {
-    return {
-      eventTarget: null
-    }
-  },
-  computed: {
-    listeners () {
-      return {
-        ...this.$listeners,
-        confirm: this.onConfirm
-      }
-    }
-  },
-  methods: {
-    show (eventTarget) {
-      this.eventTarget = eventTarget || {}
-      this.$refs.confirmDialg.show()
-    },
-    onConfirm (done) {
-      const value = this.$refs.eventTargetPicker.getValue()
-      if (value) {
-        this.$emit('confirm', {
-          value,
-          snapshot: this.$refs.eventTargetPicker.getSnapshot(),
-          done
-        })
-      }
-    }
-  }
-}
-</script>

+ 0 - 25
src/global-api.js

@@ -1,25 +0,0 @@
-import {
-  showLoading,
-  closeLoading
-} from '@/utils/pop'
-
-export function injectGlobalApi (Vue) {
-  Vue.config.productionTip = false
-  Vue.config.errorHandler = err => {
-    closeLoading()
-    throw (err || 'custom reject')
-  }
-
-  Vue.prototype.__PLACEHOLDER__ = __PLACEHOLDER__
-  Vue.prototype.__WECHAT__ = __WECHAT__
-
-  Vue.prototype.$showLoading = showLoading
-  Vue.prototype.$closeLoading = closeLoading
-
-  Vue.prototype.$designProgram = function (id) {
-    window.open(this.$router.resolve({
-      name: 'program',
-      params: { id }
-    }).href, '_blank')
-  }
-}

+ 4 - 4
src/layout/components/Navbar/Profile/components/UserInfoItem.vue

@@ -67,8 +67,8 @@ import {
   validEmail
 } from '@/utils/validate'
 import {
-  authcodeSend,
-  authcodeCheck
+  sendVerificationCode,
+  checkVerificationCode
 } from '@/api/user'
 
 const COUNTDOWN = 60
@@ -182,7 +182,7 @@ export default {
       if (!this.checkValue()) {
         return
       }
-      authcodeSend({
+      sendVerificationCode({
         [this.config.typeKey]: this.cValue
       }).then(
         ({ success, errMessage }) => {
@@ -221,7 +221,7 @@ export default {
         })
         return
       }
-      authcodeCheck({
+      checkVerificationCode({
         [this.config.typeKey]: this.cValue,
         [this.config.codeKey]: this.code
       }).then(

+ 5 - 5
src/layout/components/Navbar/Profile/index.vue

@@ -151,8 +151,8 @@ import { mapGetters } from 'vuex'
 import {
   userinfo,
   updateUser,
-  getTicket,
-  getQrcode
+  getWechatQr,
+  getAppletQr
 } from '@/api/user'
 import { GATEWAY } from '@/constant'
 import UserInfoItem from './components/UserInfoItem'
@@ -285,7 +285,7 @@ export default {
       return user.attributes[key][0]
     },
     updateUser (data, meesage) {
-      return updateUser(this.user.id, data, meesage).then(() => {
+      return updateUser(data, meesage).then(() => {
         this.user = { ...this.user, ...data }
       })
     },
@@ -357,7 +357,7 @@ export default {
       options.loading = true
       options.retry = false
       clearTimeout(this.$timer)
-      getTicket(this.user.id).then(
+      getWechatQr(this.user.id).then(
         ({ data }) => {
           if (!this.wechat) {
             try {
@@ -386,7 +386,7 @@ export default {
       const options = this.appletOptions
       options.loading = true
       options.retry = false
-      getQrcode({ page: process.env.VUE_APP_APPLET_PAGE, sourceUrl: GATEWAY }).then(
+      getAppletQr({ page: process.env.VUE_APP_APPLET_PAGE, sourceUrl: GATEWAY }).then(
         ({ data }) => {
           options.checking = true
           options.qr = `data:image/png;base64,${data}`

+ 73 - 26
src/main.js

@@ -4,14 +4,10 @@ import Vue from 'vue'
 import 'element-ui/lib/theme-chalk/index.css'
 import './scss/index.scss'
 
-import Element, { InputNumber } from 'element-ui'
-InputNumber.methods.handleInputChange = function (value) {
-  const newVal = value === '' ? this.min === -Infinity ? void 0 : this.min : Number(value)
-  if (!isNaN(newVal) || value === '') {
-    this.setCurrentValue(newVal)
-  }
-  this.userInput = null
-}
+import Element, {
+  MessageBox,
+  InputNumber
+} from 'element-ui'
 
 import App from './App'
 import store from './store'
@@ -21,7 +17,10 @@ import './icons'
 import './components'
 import './permission'
 
-import { injectGlobalApi } from './global-api'
+import {
+  showLoading,
+  closeLoading
+} from '@/utils/pop'
 
 const initOptions = {
   url: process.env.VUE_APP_KEYCLOAK_OPTIONS_URL,
@@ -42,37 +41,85 @@ keycloak
 
     console.log(keycloak)
 
-    // Token Refresh
-    setInterval(() => {
-      keycloak.updateToken(70).then(refreshed => {
-        if (refreshed) {
-          console.info('Token refreshed', keycloak)
-          store.commit('user/SET_TOKEN', keycloak.token)
-        } else {
-          console.warn(`Token not refreshed, valid for ${Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000)} seconds`)
-        }
-      }).catch(() => console.error('Failed to refresh token'))
-    }, 6000)
+    refreshKeycloak()
   })
-  .catch(() => console.error('Authenticated Failed'))
+  .catch(e => console.error('Authenticated Failed', e))
   .finally(startApp)
 
+function refreshKeycloak () {
+  // Token Refresh
+  setInterval(() => {
+    keycloak.updateToken(70).then(refreshed => {
+      if (refreshed) {
+        store.dispatch('user/refresh', keycloak).catch(() => {
+          try {
+            MessageBox.close()
+          } finally {
+            store.dispatch('user/clearToken')
+            MessageBox.confirm(
+              '账号信息发生变化,请重新登录',
+              '系统提示',
+              {
+                type: 'warning',
+                confirmButtonText: '重新登录',
+                center: true,
+                showClose: false,
+                showCancelButton: false,
+                closeOnClickModal: false,
+                closeOnPressEscape: false,
+                closeOnHashChange: false
+              }
+            ).then(() => {
+              store.dispatch('user/logout')
+            })
+          }
+        })
+      } else {
+        console.warn(`Token not refreshed, valid for ${Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000)} seconds`)
+      }
+    }).catch(e => console.error('Failed to refresh token', e))
+  }, 6000)
+}
+
 async function startApp () {
   document.body.setAttribute('version', __VERSION__)
 
+  InputNumber.methods.handleInputChange = function (value) {
+    const newVal = value === '' ? this.min === -Infinity ? void 0 : this.min : Number(value)
+    if (!isNaN(newVal) || value === '') {
+      this.setCurrentValue(newVal)
+    }
+    this.userInput = null
+  }
   Vue.use(Element)
-  Vue.prototype.$keycloak = keycloak
 
-  await store.dispatch('user/login', keycloak)
-  store.dispatch('permission/generateRoutes')
-  router.addRoutes(store.getters.permissionRoutes)
+  Vue.config.productionTip = false
+  Vue.config.errorHandler = err => {
+    closeLoading()
+    throw (err || 'custom reject')
+  }
+
+  Vue.prototype.__PLACEHOLDER__ = __PLACEHOLDER__
+  Vue.prototype.__WECHAT__ = __WECHAT__
 
-  injectGlobalApi(Vue, store, router)
+  Vue.prototype.$keycloak = keycloak
+  Vue.prototype.$showLoading = showLoading
+  Vue.prototype.$closeLoading = closeLoading
+  Vue.prototype.$designProgram = function (id) {
+    window.open(this.$router.resolve({
+      name: 'program',
+      params: { id }
+    }).href, '_blank')
+  }
 
   window._AMapSecurityConfig = {
     securityJsCode: process.env.VUE_APP_GAODE_MAP_JSCODE
   }
 
+  await store.dispatch('user/login', keycloak)
+  store.dispatch('permission/generateRoutes')
+  router.addRoutes(store.getters.permissionRoutes)
+
   new Vue({
     router,
     store,

+ 9 - 6
src/store/getters.js

@@ -28,32 +28,35 @@ const getters = {
   roles (state) {
     return state.user.roles
   },
-  accesses (state) {
-    return state.user.accesses
+  access (state) {
+    return state.user.access
   },
   permissionRoutes (state) {
     return state.permission.routes
   },
   isSuperAdmin (state, getters) {
-    return getters.accesses.has(Access.MANAGE_TENANTS)
+    return getters.access.has(Access.MANAGE_TENANTS)
   },
   isTenantAdmin (state, getters) {
-    return getters.isSuperAdmin || getters.accesses.has(Access.MANAGE_TENANT)
+    return getters.isSuperAdmin || getters.access.has(Access.MANAGE_TENANT)
   },
   isGroupAdmin (state, getters) {
-    return getters.isTenantAdmin || getters.accesses.has(Access.MANAGE_GROUP)
+    return getters.isTenantAdmin || getters.access.has(Access.MANAGE_GROUP)
   },
   isTopGroupAdmin (state, getters) {
     return getters.isTenantAdmin || getters.isGroupAdmin && getters.tenant === getters.org
   },
   isOperator (state, getters) {
-    return getters.accesses.has(Access.MANAGE_CALENDAR)
+    return getters.access.has(Access.MANAGE_CALENDAR)
   },
   isValid (state, getters) {
     return getters.token && (getters.tenant || getters.isSuperAdmin)
   },
   account (state) {
     return state.user.account
+  },
+  canManageUsers (state) {
+    return state.user.resourceAccess.has('manage-users')
   }
 }
 

+ 1 - 1
src/store/modules/permission.js

@@ -42,7 +42,7 @@ const actions = {
     commit('SET_ROUTES', constantRoutes.concat(
       __DEV__ && rootGetters.isSuperAdmin
         ? asyncRoutes
-        : filterAsyncRoutes(asyncRoutes, rootGetters.accesses)
+        : filterAsyncRoutes(asyncRoutes, rootGetters.access)
     ))
   }
 }

+ 81 - 33
src/store/modules/user.js

@@ -19,8 +19,8 @@ const state = {
   name: '',
   avatar: '',
   roles: new Set(),
-  accesses: new Set(),
-  account: ''
+  access: new Set(),
+  resourceAccess: new Set()
 }
 
 const mutations = {
@@ -60,18 +60,25 @@ const mutations = {
     console.log('roles', roles)
     state.roles = roles
   },
-  SET_ACCESSES (state, accesses) {
-    console.log('accesses', accesses)
-    state.accesses = accesses
+  SET_ACCESS (state, access) {
+    console.log('access', access)
+    state.access = access
   },
-  SET_ACCOUNT (state, account) {
-    state.account = account
+  SET_RESOURCE_ACCESS (state, resourceAccess) {
+    console.log('resourceAccess', resourceAccess)
+    state.resourceAccess = resourceAccess
   }
 }
 
-function parseAccess (realmAccess, resourceAccess) {
+function parseAccess (realmAccess, resourceAccess, options) {
+  options = {
+    access: true,
+    ...options
+  }
   const roleSet = new Set([Role.VISITOR])
   const accessSet = new Set()
+  const resourceAccessSet = new Set()
+
   if (realmAccess) {
     const roles = new Set(Object.values(Role))
     realmAccess.roles.forEach(role => {
@@ -80,48 +87,43 @@ function parseAccess (realmAccess, resourceAccess) {
       }
     })
   }
-  roleSet.forEach(role => {
-    RoleAccess[role].forEach(access => {
-      accessSet.add(access)
+  if (options.access) {
+    roleSet.forEach(role => {
+      RoleAccess[role].forEach(access => {
+        accessSet.add(access)
+      })
     })
-  })
-  if (resourceAccess?.[process.env.VUE_APP_BACKEND_CLIENT]) {
-    resourceAccess[process.env.VUE_APP_BACKEND_CLIENT].roles.forEach(role => {
-      accessSet.add(role)
+  }
+  if (resourceAccess) {
+    Object.keys(resourceAccess).forEach(key => {
+      console.log('resourceAccess', key)
+      resourceAccess[key].roles.forEach(role => resourceAccessSet.add(role))
     })
   }
-  return { roleSet, accessSet }
+  return { roleSet, accessSet, resourceAccessSet }
 }
 
 const actions = {
-  async login ({ commit, rootGetters }, keycloak) {
+  async login ({ commit, dispatch, rootGetters }, keycloak) {
     if (keycloak.authenticated) {
       inst()
-      const { tenant, sub, preferred_username, family_name, given_name, avatar } = keycloak.tokenParsed
-      const { roleSet, accessSet } = parseAccess(keycloak.realmAccess, keycloak.resourceAccess)
-      commit('SET_TOKEN', keycloak.token)
-      commit('SET_ID', sub)
-      commit('SET_NAME', family_name && given_name
-        ? /[a-zA-z]/.test(family_name)
-          ? `${given_name} ${family_name}`
-          : `${family_name}${given_name}`
-        : preferred_username)
-      commit('SET_AVATAR', avatar)
+      dispatch('updateUser', keycloak)
+      const { tenant } = keycloak.tokenParsed
+      const { roleSet, accessSet, resourceAccessSet } = parseAccess(keycloak.realmAccess, keycloak.resourceAccess)
       commit('SET_ROLES', roleSet)
-      commit('SET_ACCESSES', accessSet)
-      commit('SET_ACCOUNT', preferred_username)
+      commit('SET_ACCESS', accessSet)
+      commit('SET_RESOURCE_ACCESS', resourceAccessSet)
       if (rootGetters.isSuperAdmin) {
+        let randomTenant = { path: '', label: '请选择租户' }
         try {
           const { data } = await getTenantsByQuery({ pageSize: 1, pageNum: 1 }, false)
           if (data.length) {
-            commit('SET_TENANT', data[0])
-          } else {
-            commit('SET_TENANT', { path: '', label: '请选择租户' })
+            randomTenant = data[0]
           }
         } catch (e) {
-          commit('SET_TENANT', { path: '', label: '请选择租户' })
           console.log(e)
         }
+        commit('SET_TENANT', randomTenant)
       } else if (tenant?.length) {
         tenant.sort((a, b) => a.length - b.length)
         commit('SET_TENANT_KEY', tenant[0])
@@ -129,6 +131,17 @@ const actions = {
       }
     }
   },
+  updateUser ({ commit }, keycloak) {
+    const { sub, preferred_username, family_name, given_name, avatar } = keycloak.tokenParsed
+    commit('SET_TOKEN', keycloak.token)
+    commit('SET_ID', sub)
+    commit('SET_NAME', family_name && given_name
+      ? /[a-zA-z]/.test(family_name)
+        ? `${given_name} ${family_name}`
+        : `${family_name}${given_name}`
+      : preferred_username)
+    commit('SET_AVATAR', avatar)
+  },
   logout () {
     // 登出将跳转页面,所以不需其他操作
     Vue.prototype.$keycloak.logout()
@@ -138,7 +151,42 @@ const actions = {
     commit('SET_TOKEN', '')
     commit('SET_TENANT_ID', '')
     Vue.prototype.$keycloak.refreshToken = null
+  },
+  refresh ({ commit, dispatch, state, rootGetters }, keycloak) {
+    console.log('Keycloak refreshed', keycloak)
+    const { roleSet, resourceAccessSet } = parseAccess(keycloak.realmAccess, keycloak.resourceAccess, { access: false })
+    if (hasDiff(roleSet, state.roles)) {
+      console.log('role updated')
+      return Promise.reject()
+    }
+    const { tenant } = keycloak.tokenParsed
+    if (!rootGetters.isSuperAdmin && tenant?.length) {
+      tenant.sort((a, b) => a.length - b.length)
+      if (tenant[0] !== state.tenantKey) {
+        console.log('tenant updated')
+        return Promise.reject()
+      }
+      if (tenant[tenant.length - 1] !== state.orgKey) {
+        console.log('org updated')
+        return Promise.reject()
+      }
+    }
+    dispatch('updateUser', keycloak)
+    commit('SET_RESOURCE_ACCESS', resourceAccessSet)
+    return Promise.resolve()
+  }
+}
+
+function hasDiff (newSet, oldSet) {
+  if (newSet.size !== oldSet.size) {
+    return true
+  }
+  for (const role of newSet) {
+    if (!oldSet.has(role)) {
+      return true
+    }
   }
+  return false
 }
 
 export default {

+ 0 - 6
src/views/device/index.vue

@@ -11,12 +11,6 @@
       :schema="schema"
       @row-click="onRowClick"
     />
-    <!-- <event-target-dialog
-      ref="eventTargetDialog"
-      title="默认播放配置"
-      :ratio="ratio"
-      @confirm="onConfirm"
-    /> -->
     <confirm-dialog
       ref="eventTargetDialog"
       size="lg fixed"

+ 2 - 2
src/views/platform/tenant/index.vue

@@ -45,7 +45,7 @@ import {
   getTenants,
   addTenant,
   updateGroup,
-  deleteGroup
+  deleteTenant
 } from '@/api/user'
 
 export default {
@@ -140,7 +140,7 @@ export default {
         { type: 'warning' }
       ).then(() => {
         const loading = this.$showLoading()
-        deleteGroup(tenant)
+        deleteTenant(tenant)
           .then(() => {
             this.$message({
               type: 'success',

+ 3 - 4
src/views/realm/user/Settings.vue

@@ -133,7 +133,7 @@
 <script>
 import { mapGetters } from 'vuex'
 import {
-  updateUser,
+  toggleUser,
   deleteUser,
   getUserGroups,
   getUserCredentials,
@@ -252,10 +252,9 @@ export default {
     },
     onToggleEnable () {
       const enabled = !this.user.enabled
-      updateUser(
+      toggleUser(
         this.user.id,
-        { enabled },
-        enabled ? '启用' : '禁用'
+        enabled
       ).then(() => {
         this.user.enabled = enabled
       })