Files
iotlcm/server/internal/logic/app/app_access.go
T

398 lines
11 KiB
Go

package app
import (
"context"
"strings"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/consts"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/contexts"
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/mcache"
"github.com/gogf/gf/v2/errors/gerror"
)
type appFeatureAccessRule struct {
Feature string
Permissions []string
Routes []string
}
// appFeatureAccessRules maps mini-program business features to existing console
// menu permissions in sys_menu.perms. It deliberately avoids role names so the
// app follows the same role-menu binding model as the admin console.
var appFeatureAccessRules = []appFeatureAccessRule{
{
Feature: "card:list",
Permissions: []string{"cpa:terminal:user", "cpm:iot:tSimCardInfo:list"},
Routes: []string{"/pages/card/index"},
},
{
Feature: "card:detail",
Permissions: []string{"cpm:iot:tSimCardInfo:view", "cpm:iot:tSimCardInfo:list"},
Routes: []string{"/pages/card/views/detail/index"},
},
{
Feature: "package:view",
Permissions: []string{
"cpm:iot:tSimCardBindPkg:list",
"cpm:iot:tSimFlowPackageInfo:list",
"cpm:iot:tSimFlowPackageInfo:view",
"cpm:iot:tSimCardBindPkg:getPkgInfo",
},
Routes: []string{"/pages/card/views/packageDetail/index"},
},
{
Feature: "card:bind",
Permissions: []string{consts.SysCheckPermissionCurrentUser},
},
{
Feature: "card:renew",
Permissions: []string{"cpm:iot:tSimCardRenew:batch:confirm"},
Routes: []string{
"/pages/business/views/renew/index",
"/pages/business/views/cardRenew/index",
},
},
{
Feature: "card:renew:submit",
Permissions: []string{"cpm:iot:tSimCardRenew:batch:confirm"},
},
{
Feature: "card:addon",
Permissions: []string{
"cpm:iot:tSimCardBindPkg:list",
"cpm:iot:tSimFlowPackageInfo:view",
"cpm:iot:tSimCardBindPkg:getPkgInfo",
},
Routes: []string{"/pages/business/views/addon/index"},
},
{
Feature: "card:change",
Permissions: []string{"cpm:iot:tSimCardChange:batch:submit"},
Routes: []string{"/pages/business/views/change/index"},
},
{
Feature: "card:change:submit",
Permissions: []string{"cpm:iot:tSimCardChange:batch:submit"},
},
{
Feature: "card:allocate",
Permissions: []string{
"cpm:iot:tSimCardAllocate:targets&cpm:iot:tSimCardAllocate:input:prepare&cpm:iot:tSimCardAllocate:batch:submit",
},
Routes: []string{"/pages/business/views/allocate/index"},
},
{
Feature: "card:stop",
Permissions: []string{"cpm:iot:tSimCardStop:input:submit"},
},
{
Feature: "card:start",
Permissions: []string{"cpm:iot:tSimCardStart:input:submit"},
},
{
Feature: "card:restart",
Permissions: []string{"cpm:iot:tSimCardRestart:input:submit"},
},
{
Feature: "card:dataStart",
Permissions: []string{"cpm:iot:tSimCardDataStart:input:submit"},
},
{
Feature: "card:dataStop",
Permissions: []string{"cpm:iot:tSimCardDataStop:input:submit"},
},
{
Feature: "card:diagnosis",
Permissions: []string{
"cpm:iot:tSimdiagnose:info",
"cpm:iot:tSimdiagnose:flow",
"cpm:iot:tSimCardInfo:querySimSession",
"cpm:iot:tSimCardInfo:querySimStatus",
},
Routes: []string{"/pages/business/views/diagnosis/index"},
},
{
Feature: "warn:view",
Permissions: []string{
"cpm:iot:simWarningConfig:list",
"cpm:iot:simWarningConfig:view",
"cpm:iot:simWarningConfig:save",
"cpm:iot:tSimWarningConfig:input:submit",
"cpm:iot:tSimWarningConfig:range:submit",
"cpm:iot:tSimWarningConfig:excel:submit",
},
Routes: []string{"/pages/business/views/warning/index"},
},
{
Feature: "order:list",
Permissions: []string{
"cpm:common:tBalanceDetail:list",
"cpm:common:tFinanceApply:list",
"cpm:gen:tFinanceApply:list",
},
Routes: []string{"/pages/business/views/order/index"},
},
{
Feature: "order:detail",
Permissions: []string{
"cpm:common:tBalanceDetail:view",
"cpm:common:tBalanceDetail:list",
"cpm:common:tFinanceApply:view",
"cpm:common:tFinanceApply:list",
"cpm:gen:tFinanceApply:list",
},
},
{
Feature: "customer:list",
Permissions: []string{"cpm:agent:dept:list", "cpm:agent:tAgentEnterprise:list"},
Routes: []string{"/pages/business/views/customer/index"},
},
{
Feature: "customer:detail",
Permissions: []string{"cpm:agent:tAgentEnterprise:view", "cpm:agent:tAgentEnterprise:list"},
Routes: []string{"/pages/business/views/customerDetail/index"},
},
{
Feature: "message:view",
Permissions: []string{consts.SysCheckPermissionCurrentUser, "cpm:system:notice:list"},
Routes: []string{"/pages/message/index", "/pages/message/views/cardDetail/index", "/pages/message/views/systemDetail/index"},
},
{Feature: "workorder:reply", Permissions: []string{"cpm:gen:tWoCommunication:message"}},
{Feature: "workorder:resolve", Permissions: []string{"cpm:gen:tWoMain:resolve"}},
{Feature: "workorder:transfer", Permissions: []string{"cpm:gen:tWoMain:transfer"}},
{Feature: "workorder:close", Permissions: []string{"cpm:gen:tWoMain:close"}},
{
Feature: "workorder:list",
Permissions: []string{"cpm:gen:tWoMain:list"},
Routes: []string{"/pages/business/views/workOrder/index"},
},
{
Feature: "workorder:create",
Permissions: []string{"cpm:gen:tWoMain:edit"},
Routes: []string{"/pages/business/views/workOrder/index", "/pages/business/views/workOrderCreate/index"},
},
{
Feature: "workorder:detail",
Permissions: []string{"cpm:gen:tWoMain:view", "cpm:gen:tWoMain:list"},
Routes: []string{"/pages/business/views/workOrderDetail/index"},
},
}
func appEnsureFeatureAccess(ctx context.Context, feature string) error {
feature = strings.TrimSpace(feature)
if feature == "" {
return nil
}
configured, err := appAccessConfigured(ctx)
if err != nil {
return err
}
if !configured || contexts.IsSuperAdmin(ctx) {
return nil
}
userId := contexts.GetUserId(ctx)
if userId == 0 {
return gerror.New("登录已过期")
}
requiredCodes := appFeaturePermissionCandidates(feature)
if len(requiredCodes) == 0 {
return nil
}
accessCodes, _, err := mcache.GetUserAccessCodeList(ctx, userId)
if err != nil {
return err
}
for _, requiredCode := range requiredCodes {
if appAccessCodesMatchExpression(accessCodes, requiredCode) {
return nil
}
}
return gerror.New("暂无操作权限")
}
func appAccessCodesMatchExpression(accessCodes []string, expression string) bool {
parts := appPermissionExpressionParts(expression)
if len(parts) == 0 {
return false
}
for _, part := range parts {
matched := false
for _, accessCode := range accessCodes {
if appMatchAccessCode(accessCode, part) {
matched = true
break
}
}
if !matched {
return false
}
}
return true
}
func appMatchAccessCode(pattern string, code string) bool {
pattern = appNormalizePermissionCode(pattern)
code = appNormalizePermissionCode(code)
if pattern == "" || code == "" {
return false
}
if pattern == code || pattern == "*" || pattern == "cpm:*" {
return true
}
if strings.HasSuffix(pattern, "*") {
return strings.HasPrefix(code, pattern[:len(pattern)-1])
}
return false
}
func appFeaturePermissionCandidates(feature string) []string {
feature = appNormalizeFeatureKey(feature)
if feature == "" {
return nil
}
if feature == "*" {
return []string{"*"}
}
codes := make([]string, 0)
for _, rule := range appFeatureAccessRules {
if rule.Feature != feature {
continue
}
for _, permission := range rule.Permissions {
codes = appendUniqueString(codes, appNormalizePermissionExpression(permission))
}
}
if len(codes) == 0 && strings.HasPrefix(feature, consts.SysCheckPermissionPrefix) {
codes = appendUniqueString(codes, appNormalizePermissionCode(feature))
}
return codes
}
func appFeaturesByPermission(permission string) []string {
permission = appNormalizePermissionCode(permission)
if permission == "" {
return nil
}
features := make([]string, 0)
for _, rule := range appFeatureAccessRules {
for _, rulePermission := range rule.Permissions {
if strings.Contains(rulePermission, "&") {
continue
}
if appMatchAccessCode(permission, rulePermission) || appMatchAccessCode(rulePermission, permission) {
features = appendUniqueString(features, rule.Feature)
break
}
}
}
return features
}
func appRoutesByFeature(feature string) []string {
feature = appNormalizeFeatureKey(feature)
routes := make([]string, 0)
for _, rule := range appFeatureAccessRules {
if rule.Feature != feature {
continue
}
for _, route := range rule.Routes {
routes = appendUniqueString(routes, route)
}
}
return routes
}
func appKnownPermissionCodes() []string {
codes := make([]string, 0)
for _, rule := range appFeatureAccessRules {
for _, permission := range rule.Permissions {
for _, part := range appPermissionExpressionParts(permission) {
codes = appendUniqueString(codes, appNormalizePermissionCode(part))
}
}
}
return codes
}
func appAppendFeaturesByPermissionSet(accessPermissions []string, appendFeature func(string)) {
if len(accessPermissions) == 0 || appendFeature == nil {
return
}
for _, rule := range appFeatureAccessRules {
for _, permission := range rule.Permissions {
if appAccessCodesMatchExpression(accessPermissions, permission) {
appendFeature(rule.Feature)
break
}
}
}
}
func appMenuPermCandidates() []string {
values := make([]string, 0)
for _, permission := range appKnownPermissionCodes() {
if permission == "" || permission == consts.SysCheckPermissionCurrentUser {
continue
}
values = appendUniqueString(values, permission)
if strings.HasPrefix(permission, consts.SysCheckPermissionMenuPrefix) {
values = appendUniqueString(values, strings.TrimPrefix(permission, consts.SysCheckPermissionMenuPrefix))
}
}
return values
}
func appNormalizeFeatureKey(value string) string {
value = strings.TrimSpace(value)
if value == "" {
return ""
}
if value == "*" || value == "cpm:*" {
return "*"
}
return value
}
func appNormalizePermissionCode(value string) string {
value = strings.TrimSpace(value)
if value == "" {
return ""
}
for strings.HasPrefix(value, consts.SysCheckPermissionMenuPrefix+consts.SysCheckPermissionMenuPrefix) {
value = strings.TrimPrefix(value, consts.SysCheckPermissionMenuPrefix)
}
if value == "*" ||
value == consts.SysCheckPermissionCurrentUser ||
value == consts.SysCheckPermissionTerminalUser ||
strings.HasPrefix(value, consts.SysCheckPermissionMenuPrefix) ||
strings.HasPrefix(value, "cpa:") ||
strings.HasPrefix(value, consts.SysCheckPermissionRolePrefix) ||
strings.HasPrefix(value, consts.SysCheckPermissionDeptPrefix) ||
strings.HasPrefix(value, consts.SysCheckPermissionPostPrefix) ||
strings.HasPrefix(value, consts.SysCheckPermissionUserPrefix) {
return value
}
return consts.SysCheckPermissionMenuPrefix + value
}
func appNormalizePermissionExpression(value string) string {
parts := appPermissionExpressionParts(value)
if len(parts) == 0 {
return ""
}
return strings.Join(parts, "&")
}
func appPermissionExpressionParts(value string) []string {
rawParts := strings.Split(strings.TrimSpace(value), "&")
parts := make([]string, 0, len(rawParts))
for _, part := range rawParts {
part = appNormalizePermissionCode(part)
if part != "" {
parts = appendUniqueString(parts, part)
}
}
return parts
}