feat(admin): 增加超级管理员逻辑

This commit is contained in:
Aaron3S
2021-09-01 16:56:12 +08:00
parent 559cf4aa19
commit a56fd98c9d
19 changed files with 184 additions and 146 deletions

View File

@@ -135,38 +135,48 @@ func (h *Handler) CreateCluster() iris.Handler {
return return
} }
_ = tx.Commit() _ = tx.Commit()
go func() {
req.Status.Phase = clusterStatusInitializing if !profile.IsAdministrator {
if e := h.clusterService.Update(req.Name, &req.Cluster, common.DBOptions{}); e != nil { go func() {
server.Logger().Errorf("cna not update cluster status %s", err) req.Status.Phase = clusterStatusInitializing
return
}
if err := client.CreateDefaultClusterRoles(); err != nil {
req.Status.Phase = clusterStatusFailed
req.Status.Message = err.Error()
if e := h.clusterService.Update(req.Name, &req.Cluster, common.DBOptions{}); e != nil { if e := h.clusterService.Update(req.Name, &req.Cluster, common.DBOptions{}); e != nil {
server.Logger().Errorf("cna not update cluster status %s", err) server.Logger().Errorf("cna not update cluster status %s", err)
return return
} }
server.Logger().Errorf("cna not init built in clusterroles %s", err) if err := client.CreateDefaultClusterRoles(); err != nil {
return req.Status.Phase = clusterStatusFailed
} req.Status.Message = err.Error()
if err := h.updateUserCert(client, &binding); err != nil { if e := h.clusterService.Update(req.Name, &req.Cluster, common.DBOptions{}); e != nil {
req.Status.Phase = clusterStatusFailed server.Logger().Errorf("cna not update cluster status %s", err)
req.Status.Message = err.Error() return
}
server.Logger().Errorf("cna not init built in clusterroles %s", err)
return
}
if err := h.updateUserCert(client, &binding); err != nil {
req.Status.Phase = clusterStatusFailed
req.Status.Message = err.Error()
if e := h.clusterService.Update(req.Name, &req.Cluster, common.DBOptions{}); e != nil {
server.Logger().Errorf("cna not update cluster status %s", err)
return
}
server.Logger().Errorf("cna not create cluster user %s", err)
return
}
req.Status.Phase = clusterStatusCompleted
if e := h.clusterService.Update(req.Name, &req.Cluster, common.DBOptions{}); e != nil { if e := h.clusterService.Update(req.Name, &req.Cluster, common.DBOptions{}); e != nil {
server.Logger().Errorf("cna not update cluster status %s", err) server.Logger().Errorf("cna not update cluster status %s", err)
return return
} }
server.Logger().Errorf("cna not create cluster user %s", err) }()
return } else {
}
req.Status.Phase = clusterStatusCompleted req.Status.Phase = clusterStatusCompleted
if e := h.clusterService.Update(req.Name, &req.Cluster, common.DBOptions{}); e != nil { if e := h.clusterService.Update(req.Name, &req.Cluster, common.DBOptions{}); e != nil {
server.Logger().Errorf("cna not update cluster status %s", err) server.Logger().Errorf("cna not update cluster status %s", err)
return return
} }
}() }
ctx.Values().Set("data", &req) ctx.Values().Set("data", &req)
} }
} }
@@ -245,26 +255,30 @@ func (h *Handler) SearchClusters() iris.Handler {
} }
result := make([]Cluster, 0) result := make([]Cluster, 0)
for i := range clusters { for i := range clusters {
c := Cluster{Cluster: clusters[i]} c := Cluster{Cluster: clusters[i]}
bs, err := h.clusterBindingService.GetClusterBindingByClusterName(c.Name, common.DBOptions{}) if profile.IsAdministrator {
if err != nil { c.Accessable = true
ctx.StatusCode(iris.StatusInternalServerError) } else {
ctx.Values().Set("message", err.Error()) bs, err := h.clusterBindingService.GetClusterBindingByClusterName(c.Name, common.DBOptions{})
return if err != nil {
} ctx.StatusCode(iris.StatusInternalServerError)
c.MemberCount = len(bs) ctx.Values().Set("message", err.Error())
mbs, err := h.clusterBindingService.GetClusterBindingByClusterName(clusters[i].Name, common.DBOptions{}) return
if err != nil { }
ctx.StatusCode(iris.StatusBadRequest) c.MemberCount = len(bs)
ctx.Values().Set("message", err) mbs, err := h.clusterBindingService.GetClusterBindingByClusterName(clusters[i].Name, common.DBOptions{})
return if err != nil {
} ctx.StatusCode(iris.StatusBadRequest)
for j := range mbs { ctx.Values().Set("message", err)
if mbs[j].UserRef == profile.Name { return
c.Accessable = true }
for j := range mbs {
if mbs[j].UserRef == profile.Name {
c.Accessable = true
}
} }
} }
result = append(result, c) result = append(result, c)
} }
if showExtra { if showExtra {
@@ -478,5 +492,4 @@ func Install(parent iris.Party) {
sp.Get("/:name/namespaces", handler.ListNamespace()) sp.Get("/:name/namespaces", handler.ListNamespace())
sp.Get("/:name/terminal/session", handler.TerminalSessionHandler()) sp.Get("/:name/terminal/session", handler.TerminalSessionHandler())
sp.Get("/:name/logging/session", handler.LoggingHandler()) sp.Get("/:name/logging/session", handler.LoggingHandler())
sp.Post("/privilege", handler.Privilege())
} }

View File

@@ -67,7 +67,7 @@ func (h *Handler) KubernetesAPIProxy() iris.Handler {
u := ctx.Values().Get("profile") u := ctx.Values().Get("profile")
profile := u.(session.UserProfile) profile := u.(session.UserProfile)
// 生成transport // 生成transport
ts, err := h.generateTLSTransport(c, profile.Name) ts, err := h.generateTLSTransport(c, profile)
if err != nil { if err != nil {
ctx.StatusCode(iris.StatusInternalServerError) ctx.StatusCode(iris.StatusInternalServerError)
ctx.Values().Set("message", err) ctx.Values().Set("message", err)
@@ -92,13 +92,17 @@ func (h *Handler) KubernetesAPIProxy() iris.Handler {
ctx.Values().Set("message", err) ctx.Values().Set("message", err)
return return
} }
canVisitAll, err := k.CanVisitAllNamespace(profile.Name) canVisitAll := false
if err != nil { if profile.IsAdministrator {
ctx.StatusCode(iris.StatusInternalServerError) canVisitAll = true
ctx.Values().Set("message", err) } else {
return canVisitAll, err = k.CanVisitAllNamespace(profile.Name)
if err != nil {
ctx.StatusCode(iris.StatusInternalServerError)
ctx.Values().Set("message", err)
return
}
} }
//
apiUrl, err := url.Parse(fmt.Sprintf("%s%s", c.Spec.Connect.Forward.ApiServer, proxyPath)) apiUrl, err := url.Parse(fmt.Sprintf("%s%s", c.Spec.Connect.Forward.ApiServer, proxyPath))
if err != nil { if err != nil {
ctx.StatusCode(iris.StatusInternalServerError) ctx.StatusCode(iris.StatusInternalServerError)
@@ -304,8 +308,18 @@ func fetchMultiNamespaceResource(client *http.Client, namespaces []string, apiUr
return &mergedContainer, nil return &mergedContainer, nil
} }
func (h *Handler) generateTLSTransport(c *v1Cluster.Cluster, username string) (http.RoundTripper, error) { func (h *Handler) generateTLSTransport(c *v1Cluster.Cluster, profile session.UserProfile) (http.RoundTripper, error) {
binding, err := h.clusterBindingService.GetBindingByClusterNameAndUserName(c.Name, username, common.DBOptions{}) if profile.IsAdministrator {
c := kubernetes.NewKubernetes(c)
adminConfig, err := c.Config()
if err != nil {
return nil, err
}
return rest.TransportFor(adminConfig)
}
binding, err := h.clusterBindingService.GetBindingByClusterNameAndUserName(c.Name, profile.Name, common.DBOptions{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -317,11 +331,7 @@ func (h *Handler) generateTLSTransport(c *v1Cluster.Cluster, username string) (h
KeyData: pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: c.PrivateKey}), KeyData: pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: c.PrivateKey}),
}, },
} }
ts, err := rest.TransportFor(kubeConf) return rest.TransportFor(kubeConf)
if err != nil {
return nil, err
}
return ts, nil
} }
func ensureProxyPathValid(path string) string { func ensureProxyPathValid(path string) string {

View File

@@ -86,6 +86,7 @@ func (h *Handler) Login() iris.Handler {
Email: u.Email, Email: u.Email,
Language: u.Language, Language: u.Language,
ResourcePermissions: permissions, ResourcePermissions: permissions,
IsAdministrator: u.IsAdmin,
} }
session.Set("profile", profile) session.Set("profile", profile)
ctx.StatusCode(iris.StatusOK) ctx.StatusCode(iris.StatusOK)
@@ -174,12 +175,7 @@ func (h *Handler) GetProfile() iris.Handler {
ctx.Values().Set("message", "can not parse to session user") ctx.Values().Set("message", "can not parse to session user")
return return
} }
permissions, err := h.aggregateResourcePermissions(p.Name)
if err != nil {
ctx.StatusCode(iris.StatusInternalServerError)
ctx.Values().Set("message", err.Error())
return
}
user, err := h.userService.GetByNameOrEmail(p.Name, common.DBOptions{}) user, err := h.userService.GetByNameOrEmail(p.Name, common.DBOptions{})
if err != nil { if err != nil {
ctx.StatusCode(iris.StatusInternalServerError) ctx.StatusCode(iris.StatusInternalServerError)
@@ -187,13 +183,21 @@ func (h *Handler) GetProfile() iris.Handler {
return return
} }
p = UserProfile{ p = UserProfile{
Name: user.Name, Name: user.Name,
NickName: user.NickName, NickName: user.NickName,
Email: user.Email, Email: user.Email,
Language: user.Language, Language: user.Language,
ResourcePermissions: permissions, IsAdministrator: user.IsAdmin,
}
if !user.IsAdmin {
permissions, err := h.aggregateResourcePermissions(p.Name)
if err != nil {
ctx.StatusCode(iris.StatusInternalServerError)
ctx.Values().Set("message", err.Error())
return
}
p.ResourcePermissions = permissions
} }
session.Set("profile", p) session.Set("profile", p)
ctx.StatusCode(iris.StatusOK) ctx.StatusCode(iris.StatusOK)
ctx.Values().Set("data", p) ctx.Values().Set("data", p)
@@ -214,7 +218,7 @@ func (h *Handler) ListUserNamespace() iris.Handler {
profile := u.(UserProfile) profile := u.(UserProfile)
k := kubernetes.NewKubernetes(c) k := kubernetes.NewKubernetes(c)
ns, err := k.GetUserNamespaceNames(profile.Name) ns, err := k.GetUserNamespaceNames(profile.Name, profile.IsAdministrator)
if err != nil { if err != nil {
ctx.StatusCode(iris.StatusInternalServerError) ctx.StatusCode(iris.StatusInternalServerError)
ctx.Values().Set("message", err) ctx.Values().Set("message", err)
@@ -295,7 +299,7 @@ func (h *Handler) GetClusterProfile() iris.Handler {
UserProfile: profile, UserProfile: profile,
ClusterRoles: roles, ClusterRoles: roles,
} }
if len(roles) <= 0 { if len(roles) <= 0 && !profile.IsAdministrator {
ctx.StatusCode(iris.StatusForbidden) ctx.StatusCode(iris.StatusForbidden)
return return
} }

View File

@@ -25,6 +25,7 @@ type UserProfile struct {
Email string `json:"email"` Email string `json:"email"`
Language string `json:"language"` Language string `json:"language"`
ResourcePermissions map[string][]string `json:"resourcePermissions"` ResourcePermissions map[string][]string `json:"resourcePermissions"`
IsAdministrator bool `json:"isAdministrator"`
} }
type ClusterUserProfile struct { type ClusterUserProfile struct {

View File

@@ -91,6 +91,11 @@ func roleHandler() iris.Handler {
// 查询角色的 rolebinding 获取 roles // 查询角色的 rolebinding 获取 roles
p := sessions.Get(ctx).Get("profile") p := sessions.Get(ctx).Get("profile")
u := p.(session.UserProfile) u := p.(session.UserProfile)
if u.IsAdministrator {
ctx.Next()
return
}
roleBindingService := v1RoleBindingService.NewService() roleBindingService := v1RoleBindingService.NewService()
rbs, err := roleBindingService.GetRoleBindingBySubject(v1Role.Subject{ rbs, err := roleBindingService.GetRoleBindingBySubject(v1Role.Subject{
Kind: "User", Kind: "User",
@@ -142,11 +147,8 @@ func getVerbByRoute(path, method string) string {
if strings.HasSuffix(path, "search") { if strings.HasSuffix(path, "search") {
return "list" return "list"
} }
if strings.HasSuffix(path, "privilege") { return "create"
return "privilege"
} else {
return "create"
}
} }
return "" return ""
} }
@@ -209,6 +211,11 @@ func roleAccessHandler() iris.Handler {
p := sessions.Get(ctx).Get("profile") p := sessions.Get(ctx).Get("profile")
u := p.(session.UserProfile) u := p.(session.UserProfile)
if !strings.Contains(ctx.Request().URL.Path, "/proxy") && !strings.Contains(ctx.Request().URL.Path, "/ws") { if !strings.Contains(ctx.Request().URL.Path, "/proxy") && !strings.Contains(ctx.Request().URL.Path, "/ws") {
// 放通admin权限
if u.IsAdministrator {
ctx.Next()
return
}
rs := ctx.Values().Get("roles") rs := ctx.Values().Get("roles")
roles := rs.([]v1Role.Role) roles := rs.([]v1Role.Role)
requestResource := ctx.Values().GetString("resource") requestResource := ctx.Values().GetString("resource")

View File

@@ -1,7 +1,6 @@
package v1 package v1
import ( import (
"fmt"
v1 "github.com/KubeOperator/ekko/internal/model/v1" v1 "github.com/KubeOperator/ekko/internal/model/v1"
v1Role "github.com/KubeOperator/ekko/internal/model/v1/role" v1Role "github.com/KubeOperator/ekko/internal/model/v1/role"
v1User "github.com/KubeOperator/ekko/internal/model/v1/user" v1User "github.com/KubeOperator/ekko/internal/model/v1/user"
@@ -26,26 +25,7 @@ var CreateAdministrator = migrations.Migration{
Handler: func(db storm.Node) error { Handler: func(db storm.Node) error {
// //
roleAdmin := v1Role.Role{
BaseModel: v1.BaseModel{
ApiVersion: "v1",
Kind: "Role",
BuiltIn: true,
CreateAt: time.Now(),
UpdateAt: time.Now(),
},
Metadata: v1.Metadata{
Name: "Administrator",
Description: "i18n_user_administrator",
UUID: uuid.New().String(),
},
Rules: []v1Role.PolicyRule{
{
Resource: []string{"*"},
Verbs: []string{"*"},
},
},
}
roleManageClusters := v1Role.Role{ roleManageClusters := v1Role.Role{
BaseModel: v1.BaseModel{ BaseModel: v1.BaseModel{
@@ -151,27 +131,9 @@ var CreateAdministrator = migrations.Migration{
}, },
} }
// 创建绑定关系 // 创建绑定关系
binding := v1Role.Binding{
BaseModel: v1.BaseModel{
ApiVersion: "v1",
Kind: "RoleBinding",
BuiltIn: true,
CreateAt: time.Now(),
UpdateAt: time.Now()},
Metadata: v1.Metadata{
Name: fmt.Sprintf("ekko:role-binding:%s-%s", roleAdmin.Name, userAdmin.Name),
UUID: uuid.New().String(),
},
Subject: v1Role.Subject{
Kind: "User",
Name: userAdmin.Name,
},
RoleRef: roleAdmin.Name,
}
dbObjects := []interface{}{ dbObjects := []interface{}{
&roleAdmin, &roleManageClusters, &roleCommonUser, &roleManageRBAC, &roleReadOnly, &roleManageClusters, &roleCommonUser, &roleManageRBAC, &roleReadOnly,
&userAdmin, &userAdmin,
&binding,
} }
for i := range dbObjects { for i := range dbObjects {
if err := db.Save(dbObjects[i]); err != nil { if err := db.Save(dbObjects[i]); err != nil {

View File

@@ -29,7 +29,7 @@ type Interface interface {
HasPermission(attributes v1.ResourceAttributes) (PermissionCheckResult, error) HasPermission(attributes v1.ResourceAttributes) (PermissionCheckResult, error)
CreateCommonUser(commonName string) ([]byte, error) CreateCommonUser(commonName string) ([]byte, error)
CreateDefaultClusterRoles() error CreateDefaultClusterRoles() error
GetUserNamespaceNames(username string) ([]string, error) GetUserNamespaceNames(username string, options ...interface{}) ([]string, error)
CanVisitAllNamespace(username string) (bool, error) CanVisitAllNamespace(username string) (bool, error)
IsNamespacedResource(resourceName string) (bool, error) IsNamespacedResource(resourceName string) (bool, error)
CleanManagedClusterRole() error CleanManagedClusterRole() error
@@ -254,15 +254,21 @@ func (k *Kubernetes) CanVisitAllNamespace(username string) (bool, error) {
} }
return false, nil return false, nil
} }
func (k *Kubernetes) GetUserNamespaceNames(username string) ([]string, error) { func (k *Kubernetes) GetUserNamespaceNames(username string, options ...interface{}) ([]string, error) {
client, err := k.Client() client, err := k.Client()
if err != nil { if err != nil {
return nil, err return nil, err
} }
all, err := k.CanVisitAllNamespace(username) all := false
if err != nil { if len(options) > 0 {
return nil, err all = options[0].(bool)
} else {
all, err = k.CanVisitAllNamespace(username)
if err != nil {
return nil, err
}
} }
namespaceSet := collectons.NewStringSet() namespaceSet := collectons.NewStringSet()
if all { if all {
ns, err := client.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) ns, err := client.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})

View File

@@ -7,13 +7,13 @@ import Layout from "@/business/app-layout/horizontal-layout"
NProgress.configure({showSpinner: false}) // NProgress Configuration NProgress.configure({showSpinner: false}) // NProgress Configuration
const generateRoutes = async (to, from, next) => { const generateRoutes = async (to, from, next) => {
const hasRoles = store.getters.clusterRoles && store.getters.clusterRoles.length > 0 const hasRoles = store.getters.isAdmin || (store.getters.clusterRoles && store.getters.clusterRoles.length > 0)
if (hasRoles) { if (hasRoles) {
next() next()
} else { } else {
try { try {
const {clusterRoles} = await store.dispatch("user/getCurrentUser") const user = await store.dispatch("user/getCurrentUser")
const accessRoutes = await store.dispatch("permission/generateRoutes", clusterRoles) const accessRoutes = await store.dispatch("permission/generateRoutes", user)
if (accessRoutes.length > 0) { if (accessRoutes.length > 0) {
const root = { const root = {
path: "/", path: "/",

View File

@@ -11,6 +11,8 @@ const getters = {
nickName: state => state.user.nickName, nickName: state => state.user.nickName,
buttom_height: state => state.terminal.buttomHeight, buttom_height: state => state.terminal.buttomHeight,
terminal_height: state => state.terminal.terminalHeight, terminal_height: state => state.terminal.terminalHeight,
terminals: state => state.terminal.terminals terminals: state => state.terminal.terminals,
isAdmin: state => state.user.isAdmin,
} }
export default getters export default getters

View File

@@ -6,7 +6,7 @@ const state = {
addRoutes: [] addRoutes: []
} }
function hasPermission(clusterRoles, route) { function hasPermission(user, route) {
if (route.requirePermission) { if (route.requirePermission) {
return checkPermissions(route.requirePermission) return checkPermissions(route.requirePermission)
} }
@@ -14,13 +14,13 @@ function hasPermission(clusterRoles, route) {
} }
export function filterRolesRoutes(routes, clusterRoles) { export function filterRolesRoutes(routes, user) {
const res = [] const res = []
routes.forEach(route => { routes.forEach(route => {
const tmp = {...route} const tmp = {...route}
if (hasPermission(clusterRoles, tmp)) { if (hasPermission(user, tmp)) {
if (tmp.children) { if (tmp.children) {
tmp.children = filterRolesRoutes(tmp.children, clusterRoles) tmp.children = filterRolesRoutes(tmp.children, user)
} }
res.push(tmp) res.push(tmp)
} }
@@ -37,12 +37,11 @@ const mutations = {
} }
const actions = { const actions = {
generateRoutes({commit}, p) { generateRoutes({commit}, user) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const clusterRoles = p
let accessedRoutes let accessedRoutes
try { try {
accessedRoutes = filterRolesRoutes(rolesRoutes, clusterRoles) accessedRoutes = filterRolesRoutes(rolesRoutes, user)
for (const route of accessedRoutes) { for (const route of accessedRoutes) {
if (route.parent) { if (route.parent) {
let hidden = true let hidden = true

View File

@@ -11,6 +11,7 @@ const state = {
roles: [], roles: [],
cluster: "", cluster: "",
clusterRoles: [], clusterRoles: [],
isAdmin: false,
} }
const mutations = { const mutations = {
@@ -33,6 +34,9 @@ const mutations = {
SET_ROLES: (state, roles) => { SET_ROLES: (state, roles) => {
state.roles = roles state.roles = roles
}, },
SET_ADMINISTRATOR: (state, isAdmin) => {
state.isAdmin = isAdmin
},
SET_CURRENT_CLUSTER: (state, name) => { SET_CURRENT_CLUSTER: (state, name) => {
state.cluster = name state.cluster = name
}, },
@@ -91,13 +95,13 @@ const actions = {
getCurrentClusterUser(clusterName).then(data => { getCurrentClusterUser(clusterName).then(data => {
const user = data.data const user = data.data
user["roles"] = ["ADMIN"] user["roles"] = ["ADMIN"]
const {name, nickName, roles,language, clusterRoles} = user const {name, nickName, roles, language, isAdministrator, clusterRoles} = user
commit("SET_NAME", name) commit("SET_NAME", name)
commit("SET_ROLES", roles) commit("SET_ROLES", roles)
commit("SET_CLUSTER_ROLES", clusterRoles) commit("SET_CLUSTER_ROLES", clusterRoles)
commit("SET_NICK_NAME", nickName) commit("SET_NICK_NAME", nickName)
commit("SET_LANGUAGE", language) commit("SET_LANGUAGE", language)
commit("SET_ADMINISTRATOR", isAdministrator)
resolve(user) resolve(user)
}).catch(error => { }).catch(error => {
reject(error) reject(error)

View File

@@ -2,6 +2,10 @@ import store from '@/store'
export const checkPermissions = function (p) { export const checkPermissions = function (p) {
const userClusterRoles = store.getters && store.getters.clusterRoles const userClusterRoles = store.getters && store.getters.clusterRoles
const isAdmin = store.getters && store.getters.isAdmin
if (isAdmin) {
return true
}
for (const clusterRole of userClusterRoles) { for (const clusterRole of userClusterRoles) {
const scope = clusterRole.metadata.labels["kubeoperator.io/role-type"] const scope = clusterRole.metadata.labels["kubeoperator.io/role-type"]
if (clusterRole.rules.length > 0) { if (clusterRole.rules.length > 0) {

View File

@@ -11,7 +11,7 @@
</el-button-group> </el-button-group>
</template> </template>
<el-table-column min-width="20px" fix> <el-table-column min-width="60px" fix>
<template v-slot:default="{row}"> <template v-slot:default="{row}">
<el-tag type="success" v-if="row.extraClusterInfo.health">{{ $t('business.cluster.ready') }}</el-tag> <el-tag type="success" v-if="row.extraClusterInfo.health">{{ $t('business.cluster.ready') }}</el-tag>
<el-tag type="danger" v-if="!row.extraClusterInfo.health">{{ $t('business.cluster.not_ready') }}</el-tag> <el-tag type="danger" v-if="!row.extraClusterInfo.health">{{ $t('business.cluster.not_ready') }}</el-tag>
@@ -131,7 +131,7 @@ export default {
buttons: [ buttons: [
{ {
label: this.$t("commons.button.edit"), label: this.$t("commons.button.edit"),
icon: "el-icon-edit", icon: "el-icon-user",
click: (row) => { click: (row) => {
this.onDetail(row.name) this.onDetail(row.name)
}, },
@@ -234,7 +234,17 @@ export default {
}, },
onVueCreated() { onVueCreated() {
listClusters().then(data => { listClusters().then(data => {
this.items = data.data; this.items = data.data.filter((item) => {
if (this.$store.getters.isAdmin) {
return true
}
if (!checkPermissions({resource: "clusters", verb: "create"}) && !checkPermissions({
resource: "clusters",
verb: "delete"
})) {
return item.accessable
}
});
if (this.items.length === 0 && checkPermissions({resource: 'clusters', verb: 'create'})) { if (this.items.length === 0 && checkPermissions({resource: 'clusters', verb: 'create'})) {
this.guideDialogVisible = true this.guideDialogVisible = true
} }

View File

@@ -23,6 +23,10 @@
<el-table-column :label="$t('business.user.role')" min-width="100" fix> <el-table-column :label="$t('business.user.role')" min-width="100" fix>
<template v-slot:default="{row}"> <template v-slot:default="{row}">
<el-tag style="margin-left: 5px" size="small" v-for="(item,key) in row.roles" :key="key">{{ item }}</el-tag> <el-tag style="margin-left: 5px" size="small" v-for="(item,key) in row.roles" :key="key">{{ item }}</el-tag>
<el-tag v-if="row.roles.length===0 && row.isAdmin">Supper User</el-tag>
</template> </template>
</el-table-column> </el-table-column>

View File

@@ -9,13 +9,13 @@ NProgress.configure({showSpinner: false}) // NProgress Configuration
const whiteList = ["/login"] // no redirect whitelist const whiteList = ["/login"] // no redirect whitelist
const generateRoutes = async (to, from, next) => { const generateRoutes = async (to, from, next) => {
const hasPermissions = Object.keys(store.getters.permissions).length > 0 const hasPermissions = store.getters.isAdmin || Object.keys(store.getters.permissions).length > 0
if (hasPermissions) { if (hasPermissions) {
next() next()
} else { } else {
try { try {
const {resourcePermissions} = await store.dispatch("user/getCurrentUser") const user = await store.dispatch("user/getCurrentUser")
const accessRoutes = await store.dispatch("permission/generateRoutes", resourcePermissions) const accessRoutes = await store.dispatch("permission/generateRoutes", user)
if (accessRoutes.length > 0) { if (accessRoutes.length > 0) {
router.addRoute({ router.addRoute({
path: "/", path: "/",

View File

@@ -5,6 +5,7 @@ const getters = {
nickName: state => state.user.nickName, nickName: state => state.user.nickName,
language: state => state.user.language, language: state => state.user.language,
permission_routes: state => state.permission.routes, permission_routes: state => state.permission.routes,
permissions: state => state.user.permissions permissions: state => state.user.permissions,
isAdmin: state => state.user.isAdmin,
} }
export default getters export default getters

View File

@@ -5,14 +5,17 @@ const state = {
addRoutes: [] addRoutes: []
} }
function hasPermission(permissions, route) { function hasPermission(user, route) {
if (user.isAdministrator) {
return true
}
if (route.requirePermission) { if (route.requirePermission) {
for (const resource of Object.keys(permissions)) { for (const resource of Object.keys(user.resourcePermissions)) {
if (resource === "*") { if (resource === "*") {
return true return true
} }
if (route.requirePermission && route.requirePermission.resource === resource) { if (route.requirePermission && route.requirePermission.resource === resource) {
for (const verb of permissions[resource]) { for (const verb of user.resourcePermissions[resource]) {
if (verb === "*") { if (verb === "*") {
return true return true
} }
@@ -28,13 +31,13 @@ function hasPermission(permissions, route) {
} }
export function filterRolesRoutes(routes, permissions) { export function filterRolesRoutes(routes, user) {
const res = [] const res = []
routes.forEach(route => { routes.forEach(route => {
const tmp = {...route} const tmp = {...route}
if (hasPermission(permissions, tmp)) { if (hasPermission(user, tmp)) {
if (tmp.children) { if (tmp.children) {
tmp.children = filterRolesRoutes(tmp.children, permissions) tmp.children = filterRolesRoutes(tmp.children, user)
} }
res.push(tmp) res.push(tmp)
} }
@@ -51,11 +54,10 @@ const mutations = {
} }
const actions = { const actions = {
generateRoutes({commit}, p) { generateRoutes({commit}, user) {
return new Promise(resolve => { return new Promise(resolve => {
const permissions = p
let accessedRoutes let accessedRoutes
accessedRoutes = filterRolesRoutes(rolesRoutes, permissions) accessedRoutes = filterRolesRoutes(rolesRoutes, user)
commit("SET_ROUTES", accessedRoutes) commit("SET_ROUTES", accessedRoutes)
resolve(accessedRoutes) resolve(accessedRoutes)
}) })

View File

@@ -6,7 +6,8 @@ const state = {
login: false, login: false,
name: "", name: "",
language: getLanguage(), language: getLanguage(),
permissions: {} permissions: {},
isAdmin: false,
} }
const mutations = { const mutations = {
@@ -26,6 +27,9 @@ const mutations = {
state.language = language state.language = language
setLanguage(language) setLanguage(language)
}, },
SET_ADMINISTRATOR: (state, isAdministrator) => {
state.isAdmin = isAdministrator
},
SET_RESOURCE_PERMISSIONS: (state, permissions) => { SET_RESOURCE_PERMISSIONS: (state, permissions) => {
state.permissions = permissions state.permissions = permissions
}, },
@@ -76,9 +80,10 @@ const actions = {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getCurrentUser().then(data => { getCurrentUser().then(data => {
const user = data.data const user = data.data
const {name, resourcePermissions, language, nickName} = user const {name, isAdministrator, resourcePermissions, language, nickName} = user
commit("SET_NAME", name) commit("SET_NAME", name)
commit("SET_RESOURCE_PERMISSIONS", resourcePermissions) commit("SET_RESOURCE_PERMISSIONS", resourcePermissions)
commit("SET_ADMINISTRATOR", isAdministrator)
commit("SET_NICK_NAME", nickName) commit("SET_NICK_NAME", nickName)
commit("SET_LANGUAGE", language) commit("SET_LANGUAGE", language)
resolve(user) resolve(user)

View File

@@ -2,6 +2,10 @@ import store from '@/store'
export const checkPermissions = function (...ps) { export const checkPermissions = function (...ps) {
const userResourcePermissions = store.getters && store.getters.permissions const userResourcePermissions = store.getters && store.getters.permissions
const isAdmin = store.getters && store.getters.isAdmin
if (isAdmin) {
return true
}
for (const p of ps) { for (const p of ps) {
if (userResourcePermissions["*"] || userResourcePermissions[p.resource]) { if (userResourcePermissions["*"] || userResourcePermissions[p.resource]) {
if (userResourcePermissions["*"]) { if (userResourcePermissions["*"]) {