mirror of
https://github.com/1Panel-dev/KubePi.git
synced 2025-11-02 23:14:01 +08:00
feat(admin): 增加超级管理员逻辑
This commit is contained in:
@@ -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())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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{})
|
||||||
|
|||||||
@@ -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: "/",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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: "/",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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["*"]) {
|
||||||
|
|||||||
Reference in New Issue
Block a user