index.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. <template>
  2. <div>
  3. <template v-if="!loaded">
  4. <a-spin />
  5. </template>
  6. <template v-else>
  7. <!-- service -->
  8. <template v-if="service">
  9. <group :key="service" v-if="!isServiceDataEmpty" :data="getServiceData(options)" :get-tag-color="getTagColor" />
  10. <span v-else>{{ $t('iam.no_resource_policy') }}</span>
  11. </template>
  12. <template v-else v-for="service of options">
  13. <group :key="service.key" :data="service" :get-tag-color="getTagColor" />
  14. </template>
  15. </template>
  16. </div>
  17. </template>
  18. <script>
  19. import * as R from 'ramda'
  20. import { uuid } from '@/utils/utils'
  21. import { SERVICES_MAP, RESOURCES_MAP, DEFAULT_ACTIONS_KEY } from '../../constants'
  22. import { genPolicyGroups } from '../../utils'
  23. import Group from './Group'
  24. export default {
  25. name: 'PolicyViewer',
  26. components: {
  27. Group,
  28. },
  29. props: {
  30. policy: {
  31. type: Object,
  32. required: true,
  33. },
  34. service: {
  35. type: String,
  36. },
  37. resource: {
  38. type: String,
  39. },
  40. excludeResources: {
  41. type: Array,
  42. },
  43. },
  44. data () {
  45. return {
  46. loaded: false,
  47. permission: {},
  48. isServiceDataEmpty: false,
  49. }
  50. },
  51. computed: {
  52. options () {
  53. const options = {}
  54. R.forEachObjIndexed((value, key) => {
  55. const policy = value[value.length - 2]
  56. if (policy !== 'deny') {
  57. const service = value[0]
  58. const resource = value[1]
  59. const action = value[2]
  60. const serviceOption = SERVICES_MAP[service] || {}
  61. const resourceOption = RESOURCES_MAP[resource] || {}
  62. const perform = value[3]
  63. const performOpt = resourceOption.extras && resourceOption.extras.length && R.find(R.propEq('value', perform))(resourceOption.extras)
  64. const actionRet = {
  65. label: performOpt ? performOpt.label : this.$t(`policyDefaultActions.${action}`),
  66. key: performOpt ? performOpt.value : action,
  67. }
  68. // 初始化结构
  69. if (!options[service]) {
  70. options[service] = {
  71. label: serviceOption.i18n ? this.$t(serviceOption.i18n) : serviceOption.label || service,
  72. key: service,
  73. children: {
  74. [resource]: {
  75. label: resourceOption.i18n ? this.$t(resourceOption.i18n) : resourceOption.label || resource,
  76. key: resource,
  77. actions: [actionRet],
  78. },
  79. },
  80. }
  81. } else {
  82. // 初始化resource
  83. if (!options[service].children[resource]) {
  84. options[service].children[resource] = {
  85. label: resourceOption.i18n ? this.$t(resourceOption.i18n) : resourceOption.label || resource,
  86. key: resource,
  87. actions: [actionRet],
  88. }
  89. } else {
  90. // 如已有相关action,不能重复添加
  91. const actionOpt = R.find(R.propEq('key', actionRet.key))(options[service].children[resource].actions)
  92. if (!actionOpt) {
  93. options[service].children[resource].actions.push(actionRet)
  94. }
  95. }
  96. // 排除资源
  97. if (this.excludeResources && this.excludeResources.length > 0) {
  98. this.excludeResources.forEach(v => {
  99. delete options[service].children[v]
  100. })
  101. }
  102. }
  103. }
  104. }, this.permission)
  105. return options
  106. },
  107. },
  108. watch: {
  109. options: {
  110. handler (val) {
  111. if (val[this.service]?.children[this.resource]?.actions?.length > 2) {
  112. this.isServiceDataEmpty = true
  113. }
  114. },
  115. deep: true,
  116. },
  117. },
  118. created () {
  119. this.POLICY_GROUPS = genPolicyGroups()
  120. this.getPermissions()
  121. },
  122. methods: {
  123. async getPermissions () {
  124. try {
  125. const bodyData = this.genPermissionsBodyData()
  126. const response = await this.$http.post(`/v1/auth/permissions?policy=${this.policy.id}&$t=${uuid()}`, bodyData)
  127. const permission = response.data || []
  128. this.permission = permission
  129. } catch (error) {
  130. throw error
  131. } finally {
  132. this.loaded = true
  133. }
  134. },
  135. genPermissionsBodyData () {
  136. const ret = {}
  137. const scope = this.policy.scope
  138. for (let i = 0, len = this.POLICY_GROUPS.length; i < len; i++) {
  139. const item = this.POLICY_GROUPS[i]
  140. for (let j = 0, jlen = item.resources.length; j < jlen; j++) {
  141. const resource = item.resources[j]
  142. for (let k = 0, klen = DEFAULT_ACTIONS_KEY.length; k < klen; k++) {
  143. const action = DEFAULT_ACTIONS_KEY[k]
  144. ret[`${resource.resource}_${action}`] = [scope, item.service, resource.resource, action]
  145. }
  146. if (resource.extras && resource.extras) {
  147. resource.extras.forEach(extras => {
  148. ret[`${resource.resource}_${extras.action}_${extras.value}`] = [scope, item.service, resource.resource, extras.action, extras.value]
  149. })
  150. }
  151. }
  152. }
  153. return ret
  154. },
  155. getTagColor (key, value) {
  156. let str = key
  157. if (value) str += value
  158. return this.colorHash.rgb(str)
  159. },
  160. getServiceData (options = {}) {
  161. const computeChildren = options[this.service]?.children
  162. const getService = (computeChildren = {}) => {
  163. return {
  164. [this.resource]: computeChildren[this.resource],
  165. }
  166. }
  167. return {
  168. key: this.service,
  169. label: this.$t('dictionary.compute'),
  170. children: getService(computeChildren),
  171. }
  172. },
  173. },
  174. }
  175. </script>