mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	refactor: code optimization
This commit is contained in:
		@@ -56,11 +56,11 @@
 | 
			
		||||
        "autoprefixer": "^10.4.21",
 | 
			
		||||
        "code-inspector-plugin": "^0.20.9",
 | 
			
		||||
        "dotenv": "^16.3.1",
 | 
			
		||||
        "eslint": "^9.24.0",
 | 
			
		||||
        "eslint": "^9.25.1",
 | 
			
		||||
        "eslint-plugin-vue": "^10.0.0",
 | 
			
		||||
        "postcss": "^8.5.3",
 | 
			
		||||
        "prettier": "^3.5.3",
 | 
			
		||||
        "sass": "^1.86.3",
 | 
			
		||||
        "sass": "^1.87.0",
 | 
			
		||||
        "tailwindcss": "^4.1.4",
 | 
			
		||||
        "typescript": "^5.8.2",
 | 
			
		||||
        "vite": "^6.3.2",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
 | 
			
		||||
        <div class="!h-full">
 | 
			
		||||
        <div class="h-full">
 | 
			
		||||
            <el-watermark
 | 
			
		||||
                :zIndex="10000000"
 | 
			
		||||
                :width="210"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <el-container class="layout-container flex-center">
 | 
			
		||||
        <Header />
 | 
			
		||||
        <el-container class="layout-mian-height-50">
 | 
			
		||||
        <el-container class="h-[calc(100vh-50px)]">
 | 
			
		||||
            <Aside />
 | 
			
		||||
            <div class="flex-center layout-backtop">
 | 
			
		||||
                <TagsView v-if="themeConfig.isTagsview" />
 | 
			
		||||
 
 | 
			
		||||
@@ -5,10 +5,8 @@
 | 
			
		||||
            <Aside />
 | 
			
		||||
            <el-container class="flex-center layout-backtop">
 | 
			
		||||
                <Header v-if="isFixedHeader" />
 | 
			
		||||
                <!-- <el-scrollbar> -->
 | 
			
		||||
                <Header v-if="!isFixedHeader" />
 | 
			
		||||
                <Main />
 | 
			
		||||
                <!-- </el-scrollbar> -->
 | 
			
		||||
            </el-container>
 | 
			
		||||
        </div>
 | 
			
		||||
        <el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,10 +3,8 @@
 | 
			
		||||
        <Aside />
 | 
			
		||||
        <el-container class="flex-center layout-backtop">
 | 
			
		||||
            <Header v-if="isFixedHeader" />
 | 
			
		||||
            <!-- <el-scrollbar view-class="!h-full" ref="layoutDefaultsScrollbarRef"> -->
 | 
			
		||||
            <Header v-if="!isFixedHeader" />
 | 
			
		||||
            <Main />
 | 
			
		||||
            <!-- </el-scrollbar> -->
 | 
			
		||||
        </el-container>
 | 
			
		||||
        <el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>
 | 
			
		||||
    </el-container>
 | 
			
		||||
 
 | 
			
		||||
@@ -34,13 +34,14 @@ body,
 | 
			
		||||
    -webkit-tap-highlight-color: transparent;
 | 
			
		||||
    background-color: var(--bg-main-color);
 | 
			
		||||
    font-size: 14px;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    // overflow: hidden;
 | 
			
		||||
    // position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 主布局样式
 | 
			
		||||
------------------------------- */
 | 
			
		||||
.layout-container {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
 | 
			
		||||
@@ -102,10 +103,6 @@ body,
 | 
			
		||||
        transition: width 0.3s ease;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .layout-mian-height-50 {
 | 
			
		||||
        height: calc(100vh - 50px);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .layout-columns-warp {
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        display: flex;
 | 
			
		||||
@@ -259,16 +256,6 @@ body,
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 元素无法被选择 */
 | 
			
		||||
.none-select {
 | 
			
		||||
    moz-user-select: -moz-none;
 | 
			
		||||
    -moz-user-select: none;
 | 
			
		||||
    -o-user-select: none;
 | 
			
		||||
    -khtml-user-select: none;
 | 
			
		||||
    -webkit-user-select: none;
 | 
			
		||||
    -ms-user-select: none;
 | 
			
		||||
    user-select: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* custom card */
 | 
			
		||||
.card {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,13 +7,13 @@
 | 
			
		||||
                </template>
 | 
			
		||||
                <template #default="scope">
 | 
			
		||||
                    <el-button v-auth="'authcert:save'" @click="edit(scope.row, scope.$index)" type="primary" icon="edit" link></el-button>
 | 
			
		||||
                    <el-button class="ml-0.5" v-auth="'authcert:del'" type="danger" @click="deleteRow(scope.$index)" icon="delete" link></el-button>
 | 
			
		||||
                    <el-button class="!ml-0.5" v-auth="'authcert:del'" type="danger" @click="deleteRow(scope.$index)" icon="delete" link></el-button>
 | 
			
		||||
 | 
			
		||||
                    <el-button
 | 
			
		||||
                        :title="$t('ac.testConn')"
 | 
			
		||||
                        :loading="props.testConnBtnLoading && scope.$index == state.idx"
 | 
			
		||||
                        :disabled="props.testConnBtnLoading"
 | 
			
		||||
                        class="ml-0.5"
 | 
			
		||||
                        class="!ml-0.5"
 | 
			
		||||
                        type="success"
 | 
			
		||||
                        @click="testConn(scope.row, scope.$index)"
 | 
			
		||||
                        icon="Link"
 | 
			
		||||
 
 | 
			
		||||
@@ -22,8 +22,8 @@
 | 
			
		||||
                    <span
 | 
			
		||||
                        :id="node.key"
 | 
			
		||||
                        @dblclick="treeNodeDblclick(data, node)"
 | 
			
		||||
                        class="node-container flex items-center w-full cursor-pointer none-select"
 | 
			
		||||
                        :class="data.type.nodeDblclickFunc ? 'none-select' : ''"
 | 
			
		||||
                        class="node-container flex items-center w-full cursor-pointer select-none"
 | 
			
		||||
                        :class="data.type.nodeDblclickFunc ? 'select-none' : ''"
 | 
			
		||||
                    >
 | 
			
		||||
                        <span v-if="data.type.value == TagTreeNode.TagPath">
 | 
			
		||||
                            <tag-info :tag-path="data.label" />
 | 
			
		||||
 
 | 
			
		||||
@@ -324,7 +324,7 @@ const columns = [
 | 
			
		||||
    TableColumn.new('fs', 'machine.fs').isSlot().setAddWidth(25),
 | 
			
		||||
    TableColumn.new('remark', 'common.remark'),
 | 
			
		||||
    TableColumn.new('code', 'common.code'),
 | 
			
		||||
    TableColumn.new('action', 'common.operation').isSlot().setMinWidth(258).fixedRight().alignCenter(),
 | 
			
		||||
    TableColumn.new('action', 'common.operation').isSlot().setMinWidth(258).fixedRight().alignCenter().noShowOverflowTooltip(),
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
// 该用户拥有的的操作列按钮权限,使用v-if进行判断,v-auth对el-dropdown-item无效
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,10 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="tag-tree-list card">
 | 
			
		||||
    <div class="tag-tree-list card h-full flex">
 | 
			
		||||
        <Splitpanes class="default-theme">
 | 
			
		||||
            <Pane size="30" min-size="25" max-size="35">
 | 
			
		||||
                <div class="card !p-1 !mb-1 !mr-1">
 | 
			
		||||
                    <el-input v-model="filterTag" clearable :placeholder="$t('tag.nameFilterPlaceholder')" style="width: 200px; margin-right: 10px" />
 | 
			
		||||
            <Pane size="30" min-size="25" max-size="35" class="flex flex-col flex-1">
 | 
			
		||||
                <div class="card !p-1 !mb-1 !mr-1 flex justify-between">
 | 
			
		||||
                    <div class="mb-1">
 | 
			
		||||
                        <el-input v-model="filterTag" clearable :placeholder="$t('tag.nameFilterPlaceholder')" class="mr-2 !w-[200px]" />
 | 
			
		||||
                        <el-button
 | 
			
		||||
                            v-if="useUserInfo().userInfo.username == 'admin'"
 | 
			
		||||
                            v-auth="'tag:save'"
 | 
			
		||||
@@ -11,7 +12,8 @@
 | 
			
		||||
                            icon="plus"
 | 
			
		||||
                            @click="showSaveTagDialog(null)"
 | 
			
		||||
                        ></el-button>
 | 
			
		||||
                    <div class="float-right">
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <el-tooltip placement="top">
 | 
			
		||||
                            <template #content>
 | 
			
		||||
                                {{ $t('tag.tagTips1') }}
 | 
			
		||||
@@ -19,11 +21,7 @@
 | 
			
		||||
                                {{ $t('tag.tagTips2') }} <br />
 | 
			
		||||
                                {{ $t('tag.tagTips3') }}
 | 
			
		||||
                            </template>
 | 
			
		||||
                            <span>
 | 
			
		||||
                                <el-icon>
 | 
			
		||||
                                    <question-filled />
 | 
			
		||||
                                </el-icon>
 | 
			
		||||
                            </span>
 | 
			
		||||
                            <SvgIcon name="question-filled" />
 | 
			
		||||
                        </el-tooltip>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
@@ -67,8 +65,8 @@
 | 
			
		||||
            </Pane>
 | 
			
		||||
 | 
			
		||||
            <Pane min-size="40" size="70">
 | 
			
		||||
                <div class="ml-2">
 | 
			
		||||
                    <el-tabs @tab-change="tabChange" v-model="state.activeTabName" v-if="currentTag">
 | 
			
		||||
                <div class="ml-2 h-full">
 | 
			
		||||
                    <el-tabs class="h-full" @tab-change="tabChange" v-model="state.activeTabName" v-if="currentTag">
 | 
			
		||||
                        <el-tab-pane :label="$t('common.detail')" :name="TagDetail">
 | 
			
		||||
                            <el-descriptions :column="2" border>
 | 
			
		||||
                                <el-descriptions-item :label="$t('common.type')">
 | 
			
		||||
@@ -91,6 +89,7 @@
 | 
			
		||||
                        </el-tab-pane>
 | 
			
		||||
 | 
			
		||||
                        <el-tab-pane
 | 
			
		||||
                            class="h-full"
 | 
			
		||||
                            :disabled="currentTag.type != TagResourceTypeEnum.Tag.value"
 | 
			
		||||
                            :label="`${$t('tag.machine')} (${resourceCount.machine || 0})`"
 | 
			
		||||
                            :name="MachineTag"
 | 
			
		||||
@@ -99,6 +98,7 @@
 | 
			
		||||
                        </el-tab-pane>
 | 
			
		||||
 | 
			
		||||
                        <el-tab-pane
 | 
			
		||||
                            class="h-full"
 | 
			
		||||
                            :disabled="currentTag.type != TagResourceTypeEnum.Tag.value"
 | 
			
		||||
                            :label="`${$t('tag.db')} (${resourceCount.db || 0})`"
 | 
			
		||||
                            :name="DbTag"
 | 
			
		||||
@@ -107,6 +107,7 @@
 | 
			
		||||
                        </el-tab-pane>
 | 
			
		||||
 | 
			
		||||
                        <el-tab-pane
 | 
			
		||||
                            class="h-full"
 | 
			
		||||
                            :disabled="currentTag.type != TagResourceTypeEnum.Tag.value"
 | 
			
		||||
                            :label="`Redis (${resourceCount.redis || 0})`"
 | 
			
		||||
                            :name="RedisTag"
 | 
			
		||||
@@ -115,6 +116,7 @@
 | 
			
		||||
                        </el-tab-pane>
 | 
			
		||||
 | 
			
		||||
                        <el-tab-pane
 | 
			
		||||
                            class="h-full"
 | 
			
		||||
                            :disabled="currentTag.type != TagResourceTypeEnum.Tag.value"
 | 
			
		||||
                            :label="`Mongo (${resourceCount.mongo || 0})`"
 | 
			
		||||
                            :name="MongoTag"
 | 
			
		||||
@@ -490,17 +492,10 @@ const removeDeafultExpandId = (id: any) => {
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
.tag-tree-list {
 | 
			
		||||
    .tag-tree-data {
 | 
			
		||||
        height: calc(100vh - 202px);
 | 
			
		||||
 | 
			
		||||
        .el-tree-node__content {
 | 
			
		||||
            height: 40px;
 | 
			
		||||
            line-height: 40px;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .el-tree {
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        min-width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,23 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="card system-resouce-list">
 | 
			
		||||
    <div class="card system-resource-list h-full flex">
 | 
			
		||||
        <Splitpanes class="default-theme">
 | 
			
		||||
            <Pane size="25" min-size="20" max-size="30">
 | 
			
		||||
                <div class="card !p-1 mr-1">
 | 
			
		||||
                    <el-input v-model="filterResource" clearable :placeholder="$t('system.menu.filterPlaceholder')" style="width: 200px; margin-right: 10px" />
 | 
			
		||||
            <Pane size="30" min-size="25" max-size="35" class="flex flex-col flex-1">
 | 
			
		||||
                <div class="card !p-1 mr-1 flex justify-between">
 | 
			
		||||
                    <div class="mb-1">
 | 
			
		||||
                        <el-input v-model="filterResource" clearable :placeholder="$t('system.menu.filterPlaceholder')" class="mr-2 !w-[200px]" />
 | 
			
		||||
                        <el-button v-auth="perms.addResource" type="primary" icon="plus" @click="addResource(false)"></el-button>
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="float-right">
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <el-tooltip placement="top">
 | 
			
		||||
                            <template #content> {{ $t('system.menu.opTips') }} </template>
 | 
			
		||||
                            <span>
 | 
			
		||||
                            <SvgIcon name="question-filled" />
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </el-tooltip>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <el-scrollbar class="tree-data">
 | 
			
		||||
                <el-scrollbar>
 | 
			
		||||
                    <el-tree
 | 
			
		||||
                        ref="resourceTreeRef"
 | 
			
		||||
                        class="none-select"
 | 
			
		||||
                        :indent="24"
 | 
			
		||||
                        node-key="id"
 | 
			
		||||
                        :props="props"
 | 
			
		||||
@@ -62,7 +61,7 @@
 | 
			
		||||
                </el-scrollbar>
 | 
			
		||||
            </Pane>
 | 
			
		||||
 | 
			
		||||
            <Pane min-size="40">
 | 
			
		||||
            <Pane min-size="40" size="70">
 | 
			
		||||
                <div class="ml-2">
 | 
			
		||||
                    <el-tabs v-model="state.activeTabName" @tab-click="onTabClick" v-if="currentResource">
 | 
			
		||||
                        <el-tab-pane :label="$t('common.detail')" :name="ResourceDetail">
 | 
			
		||||
@@ -437,29 +436,10 @@ const removeDeafultExpandId = (id: any) => {
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
.system-resouce-list {
 | 
			
		||||
.system-resource-list {
 | 
			
		||||
    .el-tree-node__content {
 | 
			
		||||
        height: 40px;
 | 
			
		||||
        line-height: 40px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .tree-data {
 | 
			
		||||
        height: calc(100vh - 202px);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .el-tree {
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        min-width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.none-select {
 | 
			
		||||
    moz-user-select: -moz-none;
 | 
			
		||||
    -moz-user-select: none;
 | 
			
		||||
    -o-user-select: none;
 | 
			
		||||
    -khtml-user-select: none;
 | 
			
		||||
    -webkit-user-select: none;
 | 
			
		||||
    -ms-user-select: none;
 | 
			
		||||
    user-select: none;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ func AddInitFunc(initFunc InitFunc) {
 | 
			
		||||
 | 
			
		||||
// 系统启动时,调用各个模块的初始化函数
 | 
			
		||||
func InitOther() {
 | 
			
		||||
	// 调用各个默认ioc组件注册初始化,优先调用ioc初始化注册函数和注入函数(可能在后续的InitFunc中需要用到依赖实例)
 | 
			
		||||
	// 调用各个模块ioc组件注册初始化,优先调用ioc初始化注册函数和注入函数(可能在后续的InitFunc中需要用到依赖实例)
 | 
			
		||||
	for _, initIocFunc := range initIocFuncs {
 | 
			
		||||
		initIocFunc()
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ var (
 | 
			
		||||
	terminateFuncs = make([]TerminateFunc, 0)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 添加系统退出终止时执行的函数,由各个默认自行添加
 | 
			
		||||
// 添加系统退出终止时执行的函数,由各个模块自行添加
 | 
			
		||||
func AddTerminateFunc(terminateFunc TerminateFunc) {
 | 
			
		||||
	terminateFuncs = append(terminateFuncs, terminateFunc)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"mayfly-go/internal/auth/imsg"
 | 
			
		||||
	"mayfly-go/internal/auth/pkg/captcha"
 | 
			
		||||
	"mayfly-go/internal/auth/pkg/otp"
 | 
			
		||||
	"mayfly-go/internal/pkg/utils"
 | 
			
		||||
	sysapp "mayfly-go/internal/sys/application"
 | 
			
		||||
	sysentity "mayfly-go/internal/sys/domain/entity"
 | 
			
		||||
	"mayfly-go/pkg/biz"
 | 
			
		||||
@@ -18,7 +19,6 @@ import (
 | 
			
		||||
	"mayfly-go/pkg/utils/collx"
 | 
			
		||||
	"mayfly-go/pkg/utils/cryptox"
 | 
			
		||||
	"mayfly-go/pkg/ws"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -62,7 +62,7 @@ func (a *AccountLogin) Login(rc *req.Ctx) {
 | 
			
		||||
	clientIp := getIpAndRegion(rc)
 | 
			
		||||
	rc.ReqParam = collx.Kvs("username", username, "ip", clientIp)
 | 
			
		||||
 | 
			
		||||
	originPwd, err := cryptox.DefaultRsaDecrypt(loginForm.Password, true)
 | 
			
		||||
	originPwd, err := utils.DefaultRsaDecrypt(loginForm.Password, true)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "decryption password error: %s")
 | 
			
		||||
 | 
			
		||||
	account := &sysentity.Account{Username: username}
 | 
			
		||||
@@ -76,7 +76,7 @@ func (a *AccountLogin) Login(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
	if err != nil || !cryptox.CheckPwdHash(originPwd, account.Password) {
 | 
			
		||||
		nowFailCount++
 | 
			
		||||
		cache.SetStr(failCountKey, strconv.Itoa(nowFailCount), time.Minute*time.Duration(loginFailMin))
 | 
			
		||||
		cache.Set(failCountKey, nowFailCount, time.Minute*time.Duration(loginFailMin))
 | 
			
		||||
		panic(errorx.NewBizI(ctx, imsg.ErrLoginFail, "failCount", nowFailCount))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -115,7 +115,7 @@ func (a *AccountLogin) OtpVerify(rc *req.Ctx) {
 | 
			
		||||
	otpSecret := otpInfo.OtpSecret
 | 
			
		||||
 | 
			
		||||
	if !otp.Validate(otpVerify.Code, otpSecret) {
 | 
			
		||||
		cache.SetStr(failCountKey, strconv.Itoa(failCount+1), time.Minute*time.Duration(10))
 | 
			
		||||
		cache.Set(failCountKey, failCount+1, time.Minute*time.Duration(10))
 | 
			
		||||
		panic(errorx.NewBizI(ctx, imsg.ErrOtpCheckFail))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,6 @@ import (
 | 
			
		||||
	"mayfly-go/pkg/i18n"
 | 
			
		||||
	"mayfly-go/pkg/req"
 | 
			
		||||
	"mayfly-go/pkg/utils/collx"
 | 
			
		||||
	"mayfly-go/pkg/utils/jsonx"
 | 
			
		||||
	"mayfly-go/pkg/utils/netx"
 | 
			
		||||
	"mayfly-go/pkg/utils/stringx"
 | 
			
		||||
	"mayfly-go/pkg/utils/timex"
 | 
			
		||||
@@ -95,7 +94,7 @@ func useOtp(account *sysentity.Account, otpIssuer, accessToken string, refreshTo
 | 
			
		||||
		AccessToken:  accessToken,
 | 
			
		||||
		RefreshToken: refreshToken,
 | 
			
		||||
	}
 | 
			
		||||
	cache.SetStr(fmt.Sprintf("otp:token:%s", token), jsonx.ToStr(otpInfo), time.Minute*time.Duration(3))
 | 
			
		||||
	cache.Set(fmt.Sprintf("otp:token:%s", token), otpInfo, time.Minute*time.Duration(3))
 | 
			
		||||
	return otpInfo, otpUrl, token
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"mayfly-go/internal/auth/config"
 | 
			
		||||
	"mayfly-go/internal/auth/imsg"
 | 
			
		||||
	"mayfly-go/internal/auth/pkg/captcha"
 | 
			
		||||
	"mayfly-go/internal/pkg/utils"
 | 
			
		||||
	sysapp "mayfly-go/internal/sys/application"
 | 
			
		||||
	sysentity "mayfly-go/internal/sys/domain/entity"
 | 
			
		||||
	"mayfly-go/pkg/biz"
 | 
			
		||||
@@ -17,7 +18,6 @@ import (
 | 
			
		||||
	"mayfly-go/pkg/req"
 | 
			
		||||
	"mayfly-go/pkg/utils/collx"
 | 
			
		||||
	"mayfly-go/pkg/utils/cryptox"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
@@ -61,7 +61,7 @@ func (a *LdapLogin) Login(rc *req.Ctx) {
 | 
			
		||||
	clientIp := getIpAndRegion(rc)
 | 
			
		||||
	rc.ReqParam = collx.Kvs("username", username, "ip", clientIp)
 | 
			
		||||
 | 
			
		||||
	originPwd, err := cryptox.DefaultRsaDecrypt(loginForm.Password, true)
 | 
			
		||||
	originPwd, err := utils.DefaultRsaDecrypt(loginForm.Password, true)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "decryption password error: %s")
 | 
			
		||||
	// LDAP 用户本地密码为空,不允许本地登录
 | 
			
		||||
	biz.NotEmpty(originPwd, "password cannot be empty")
 | 
			
		||||
@@ -78,7 +78,7 @@ func (a *LdapLogin) Login(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		nowFailCount++
 | 
			
		||||
		cache.SetStr(failCountKey, strconv.Itoa(nowFailCount), time.Minute*time.Duration(loginFailMin))
 | 
			
		||||
		cache.Set(failCountKey, nowFailCount, time.Minute*time.Duration(loginFailMin))
 | 
			
		||||
		panic(errorx.NewBizI(ctx, imsg.ErrLoginFail, "failCount", nowFailCount))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -55,14 +55,14 @@ func (o *Oauth2Login) ReqConfs() *req.Confs {
 | 
			
		||||
func (a *Oauth2Login) OAuth2Login(rc *req.Ctx) {
 | 
			
		||||
	client, _ := a.getOAuthClient()
 | 
			
		||||
	state := stringx.Rand(32)
 | 
			
		||||
	cache.SetStr("oauth2:state:"+state, "login", 5*time.Minute)
 | 
			
		||||
	cache.Set("oauth2:state:"+state, "login", 5*time.Minute)
 | 
			
		||||
	rc.Redirect(http.StatusFound, client.AuthCodeURL(state))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *Oauth2Login) OAuth2Bind(rc *req.Ctx) {
 | 
			
		||||
	client, _ := a.getOAuthClient()
 | 
			
		||||
	state := stringx.Rand(32)
 | 
			
		||||
	cache.SetStr("oauth2:state:"+state, "bind:"+strconv.FormatUint(rc.GetLoginAccount().Id, 10),
 | 
			
		||||
	cache.Set("oauth2:state:"+state, "bind:"+strconv.FormatUint(rc.GetLoginAccount().Id, 10),
 | 
			
		||||
		5*time.Minute)
 | 
			
		||||
	rc.Redirect(http.StatusFound, client.AuthCodeURL(state))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"mayfly-go/internal/pkg/utils"
 | 
			
		||||
	"mayfly-go/pkg/biz"
 | 
			
		||||
	"mayfly-go/pkg/req"
 | 
			
		||||
	"mayfly-go/pkg/utils/cryptox"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Common struct {
 | 
			
		||||
@@ -19,7 +19,7 @@ func (c *Common) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *Common) RasPublicKey(rc *req.Ctx) {
 | 
			
		||||
	publicKeyStr, err := cryptox.GetRsaPublicKey()
 | 
			
		||||
	publicKeyStr, err := utils.GetRsaPublicKey()
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "rsa - failed to genenrate public key")
 | 
			
		||||
	rc.ResData = publicKeyStr
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ import (
 | 
			
		||||
	"mayfly-go/internal/event"
 | 
			
		||||
	msgapp "mayfly-go/internal/msg/application"
 | 
			
		||||
	msgdto "mayfly-go/internal/msg/application/dto"
 | 
			
		||||
	"mayfly-go/internal/pkg/utils"
 | 
			
		||||
	tagapp "mayfly-go/internal/tag/application"
 | 
			
		||||
	tagentity "mayfly-go/internal/tag/domain/entity"
 | 
			
		||||
	"mayfly-go/pkg/biz"
 | 
			
		||||
@@ -24,7 +25,6 @@ import (
 | 
			
		||||
	"mayfly-go/pkg/req"
 | 
			
		||||
	"mayfly-go/pkg/utils/anyx"
 | 
			
		||||
	"mayfly-go/pkg/utils/collx"
 | 
			
		||||
	"mayfly-go/pkg/utils/cryptox"
 | 
			
		||||
	"mayfly-go/pkg/utils/writerx"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
@@ -144,7 +144,7 @@ func (d *Db) ExecSql(rc *req.Ctx) {
 | 
			
		||||
	biz.ErrIsNilAppendErr(d.tagApp.CanAccess(rc.GetLoginAccount().Id, dbConn.Info.CodePath...), "%s")
 | 
			
		||||
 | 
			
		||||
	global.EventBus.Publish(rc.MetaCtx, event.EventTopicResourceOp, dbConn.Info.CodePath[0])
 | 
			
		||||
	sqlStr, err := cryptox.AesDecryptByLa(form.Sql, rc.GetLoginAccount())
 | 
			
		||||
	sqlStr, err := utils.AesDecryptByLa(form.Sql, rc.GetLoginAccount())
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "sql decoding failure: %s")
 | 
			
		||||
 | 
			
		||||
	rc.ReqParam = fmt.Sprintf("%s %s\n-> %s", dbConn.Info.GetLogDesc(), form.ExecId, sqlStr)
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,9 @@ import (
 | 
			
		||||
	"mayfly-go/internal/db/application"
 | 
			
		||||
	"mayfly-go/internal/db/domain/entity"
 | 
			
		||||
	"mayfly-go/internal/db/imsg"
 | 
			
		||||
	"mayfly-go/internal/pkg/utils"
 | 
			
		||||
	"mayfly-go/pkg/biz"
 | 
			
		||||
	"mayfly-go/pkg/req"
 | 
			
		||||
	"mayfly-go/pkg/utils/cryptox"
 | 
			
		||||
	"mayfly-go/pkg/utils/stringx"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
@@ -67,7 +67,7 @@ func (d *DataSyncTask) SaveTask(rc *req.Ctx) {
 | 
			
		||||
	task := req.BindJsonAndCopyTo[*entity.DataSyncTask](rc, form, new(entity.DataSyncTask))
 | 
			
		||||
 | 
			
		||||
	// 解码base64 sql
 | 
			
		||||
	sqlStr, err := cryptox.AesDecryptByLa(task.DataSql, rc.GetLoginAccount())
 | 
			
		||||
	sqlStr, err := utils.AesDecryptByLa(task.DataSql, rc.GetLoginAccount())
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "sql decoding failure: %s")
 | 
			
		||||
	sql := stringx.TrimSpaceAndBr(sqlStr)
 | 
			
		||||
	task.DataSql = sql
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import (
 | 
			
		||||
const MachineStatCacheKey = "mayfly:machine:%d:stat"
 | 
			
		||||
 | 
			
		||||
func SaveMachineStats(machineId uint64, stat *mcm.Stats) error {
 | 
			
		||||
	return global_cache.SetStr(fmt.Sprintf(MachineStatCacheKey, machineId), jsonx.ToStr(stat), 10*time.Minute)
 | 
			
		||||
	return global_cache.Set(fmt.Sprintf(MachineStatCacheKey, machineId), stat, 10*time.Minute)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetMachineStats(machineId uint64) (*mcm.Stats, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,25 @@ import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"mayfly-go/internal/pkg/config"
 | 
			
		||||
	"mayfly-go/pkg/cache"
 | 
			
		||||
	"mayfly-go/pkg/logx"
 | 
			
		||||
	"mayfly-go/pkg/rediscli"
 | 
			
		||||
 | 
			
		||||
	"github.com/redis/go-redis/v9"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func initRedis() {
 | 
			
		||||
// 有配置redis信息,则初始化redis。多台机器部署需要使用redis存储验证码、权限、公私钥等信息
 | 
			
		||||
func initCache() {
 | 
			
		||||
	redisCli := connRedis()
 | 
			
		||||
 | 
			
		||||
	if redisCli == nil {
 | 
			
		||||
		logx.Info("no redis configuration exists, local cache is used")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logx.Info("redis connection is successful, redis cache is used")
 | 
			
		||||
	rediscli.SetCli(connRedis())
 | 
			
		||||
	cache.SetCache(cache.NewRedisCache(redisCli))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func connRedis() *redis.Client {
 | 
			
		||||
@@ -21,7 +32,7 @@ func connRedis() *redis.Client {
 | 
			
		||||
		// logx.Panic("未找到redis配置信息")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	logx.Infof("连接redis [%s:%d]", redisConf.Host, redisConf.Port)
 | 
			
		||||
	logx.Infof("redis connecting [%s:%d]", redisConf.Host, redisConf.Port)
 | 
			
		||||
	rdb := redis.NewClient(&redis.Options{
 | 
			
		||||
		Addr:     fmt.Sprintf("%s:%d", redisConf.Host, redisConf.Port),
 | 
			
		||||
		Password: redisConf.Password, // no password set
 | 
			
		||||
@@ -30,7 +41,7 @@ func connRedis() *redis.Client {
 | 
			
		||||
	// 测试连接
 | 
			
		||||
	_, e := rdb.Ping(context.TODO()).Result()
 | 
			
		||||
	if e != nil {
 | 
			
		||||
		logx.Panicf("连接redis失败! [%s:%d][%s]", redisConf.Host, redisConf.Port, e.Error())
 | 
			
		||||
		logx.Panicf("redis connection faild! [%s:%d][%s]", redisConf.Host, redisConf.Port, e.Error())
 | 
			
		||||
	}
 | 
			
		||||
	return rdb
 | 
			
		||||
}
 | 
			
		||||
@@ -33,8 +33,8 @@ func RunWebServer() {
 | 
			
		||||
	// 初始化并赋值数据库全局变量
 | 
			
		||||
	initDb()
 | 
			
		||||
 | 
			
		||||
	// 有配置redis信息,则初始化redis。多台机器部署需要使用redis存储验证码、权限、公私钥等
 | 
			
		||||
	initRedis()
 | 
			
		||||
	// 初始化缓存
 | 
			
		||||
	initCache()
 | 
			
		||||
 | 
			
		||||
	// 数据库升级操作
 | 
			
		||||
	if err := migration.RunMigrations(global.Db); err != nil {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										129
									
								
								server/internal/pkg/utils/ctypto.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								server/internal/pkg/utils/ctypto.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
			
		||||
package utils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"mayfly-go/pkg/cache"
 | 
			
		||||
	"mayfly-go/pkg/logx"
 | 
			
		||||
	"mayfly-go/pkg/model"
 | 
			
		||||
	"mayfly-go/pkg/utils/cryptox"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// 公钥文件路径
 | 
			
		||||
	publicKeyFile = "./mayfly_rsa.pub"
 | 
			
		||||
	// 私钥文件路径
 | 
			
		||||
	privateKeyFile = "./mayfly_rsa"
 | 
			
		||||
 | 
			
		||||
	publicKeyK  = "mayfly:public-key"
 | 
			
		||||
	privateKeyK = "mayfly:private-key"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 使用系统默认的私钥解密
 | 
			
		||||
// @param base64 字符串是否使用base64编码
 | 
			
		||||
func DefaultRsaDecrypt(data string, useBase64 bool) (string, error) {
 | 
			
		||||
	// 空字符串不解密
 | 
			
		||||
	if data == "" {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
	if useBase64 {
 | 
			
		||||
		if decodeBase64, err := base64.StdEncoding.DecodeString(data); err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		} else {
 | 
			
		||||
			data = string(decodeBase64)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	priKey, err := GetRsaPrivateKey()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	val, err := cryptox.RsaDecrypt(priKey, []byte(data))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return string(val), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 获取系统的RSA公钥
 | 
			
		||||
func GetRsaPublicKey() (string, error) {
 | 
			
		||||
	if cache.UseRedisCache() {
 | 
			
		||||
		publicKey := cache.GetStr(publicKeyK)
 | 
			
		||||
		if publicKey != "" {
 | 
			
		||||
			return publicKey, nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		content, err := os.ReadFile(publicKeyFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			publicKey := cache.GetStr(publicKeyK)
 | 
			
		||||
			if publicKey != "" {
 | 
			
		||||
				return publicKey, nil
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			return string(content), nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, pubKey, err := GenerateAndSaveRSAKey()
 | 
			
		||||
	return pubKey, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 获取系统私钥
 | 
			
		||||
func GetRsaPrivateKey() (string, error) {
 | 
			
		||||
	if cache.UseRedisCache() {
 | 
			
		||||
		priKey := cache.GetStr(privateKeyK)
 | 
			
		||||
		if priKey != "" {
 | 
			
		||||
			return priKey, nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		content, err := os.ReadFile(privateKeyFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			priKey := cache.GetStr(privateKeyK)
 | 
			
		||||
			if priKey != "" {
 | 
			
		||||
				return priKey, nil
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			return string(content), nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	priKey, _, err := GenerateAndSaveRSAKey()
 | 
			
		||||
	return priKey, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 生成并保存rsa key,优先保存于磁盘,若磁盘保存失败,则保存至缓存
 | 
			
		||||
//
 | 
			
		||||
// 依次返回 privateKey, publicKey, error
 | 
			
		||||
func GenerateAndSaveRSAKey() (string, string, error) {
 | 
			
		||||
	privateKey, publicKey, err := cryptox.GenerateRSAKey(1024)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 如果使用了redis缓存,则优先存入redis
 | 
			
		||||
	if cache.UseRedisCache() {
 | 
			
		||||
		logx.Debug("系统配置了redis, rsa存入redis")
 | 
			
		||||
		cache.Set(privateKeyK, privateKey, -1)
 | 
			
		||||
		cache.Set(publicKeyK, publicKey, -1)
 | 
			
		||||
		return privateKey, publicKey, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = os.WriteFile(privateKeyFile, []byte(privateKey), 0644)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logx.ErrorTrace("RSA私钥写入磁盘文件失败, 使用缓存存储该私钥", err)
 | 
			
		||||
		cache.Set(privateKeyK, privateKey, -1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = os.WriteFile(publicKeyFile, []byte(publicKey), 0644)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logx.ErrorTrace("RSA公钥写入磁盘文件失败, 使用缓存存储该公钥", err)
 | 
			
		||||
		cache.Set(publicKeyK, publicKey, -1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return privateKey, publicKey, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AesDecryptByLa(data string, la *model.LoginAccount) (string, error) {
 | 
			
		||||
	key := []byte(la.GetAesKey())
 | 
			
		||||
	res, err := cryptox.AesDecryptBase64(data, key)
 | 
			
		||||
	return string(res), err
 | 
			
		||||
}
 | 
			
		||||
@@ -110,7 +110,7 @@ func (a *Account) ChangePassword(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
	form := req.BindJsonAndValid(rc, new(form.AccountChangePasswordForm))
 | 
			
		||||
 | 
			
		||||
	originOldPwd, err := cryptox.DefaultRsaDecrypt(form.OldPassword, true)
 | 
			
		||||
	originOldPwd, err := utils.DefaultRsaDecrypt(form.OldPassword, true)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "Wrong to decrypt old password: %s")
 | 
			
		||||
 | 
			
		||||
	account := &entity.Account{Username: form.Username}
 | 
			
		||||
@@ -119,7 +119,7 @@ func (a *Account) ChangePassword(rc *req.Ctx) {
 | 
			
		||||
	biz.IsTrueI(ctx, cryptox.CheckPwdHash(originOldPwd, account.Password), imsg.ErrOldPasswordWrong)
 | 
			
		||||
	biz.IsTrue(account.IsEnable(), "This account is not available")
 | 
			
		||||
 | 
			
		||||
	originNewPwd, err := cryptox.DefaultRsaDecrypt(form.NewPassword, true)
 | 
			
		||||
	originNewPwd, err := utils.DefaultRsaDecrypt(form.NewPassword, true)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "Wrong to decrypt new password: %s")
 | 
			
		||||
	biz.IsTrueI(ctx, utils.CheckAccountPasswordLever(originNewPwd), imsg.ErrAccountPasswordNotFollowRule)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@ package application
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"mayfly-go/internal/sys/domain/entity"
 | 
			
		||||
	"mayfly-go/internal/sys/domain/repository"
 | 
			
		||||
	"mayfly-go/pkg/base"
 | 
			
		||||
@@ -10,7 +9,6 @@ import (
 | 
			
		||||
	"mayfly-go/pkg/errorx"
 | 
			
		||||
	"mayfly-go/pkg/logx"
 | 
			
		||||
	"mayfly-go/pkg/model"
 | 
			
		||||
	"mayfly-go/pkg/utils/jsonx"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -56,16 +54,14 @@ func (a *configAppImpl) Save(ctx context.Context, config *entity.Config) error {
 | 
			
		||||
func (a *configAppImpl) GetConfig(key string) *entity.Config {
 | 
			
		||||
	config := &entity.Config{Key: key}
 | 
			
		||||
	// 优先从缓存中获取
 | 
			
		||||
	cacheStr := cache.GetStr(SysConfigKeyPrefix + key)
 | 
			
		||||
	if cacheStr != "" {
 | 
			
		||||
		json.Unmarshal([]byte(cacheStr), &config)
 | 
			
		||||
	if exist := cache.Get(SysConfigKeyPrefix+key, &config); exist {
 | 
			
		||||
		return config
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := a.GetByCond(model.NewModelCond(config).Columns("Id", "Key", "Value", "Permission")); err != nil {
 | 
			
		||||
		logx.Warnf("There is no system configuration with key = [%s]", key)
 | 
			
		||||
	} else {
 | 
			
		||||
		cache.SetStr(SysConfigKeyPrefix+key, jsonx.ToStr(config), -1)
 | 
			
		||||
		cache.Set(SysConfigKeyPrefix+key, config, -1)
 | 
			
		||||
	}
 | 
			
		||||
	return config
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -419,17 +419,15 @@ func (p *tagTreeAppImpl) GetAccountTags(accountId uint64, query *entity.TagTreeQ
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// 如用户分配了: "default/type1|code1/type2|code2/type3|code3/", 需要查询的codePathLike为: default/type1|%/type2|%/,即用户分配的标签路径是查询的子节点。
 | 
			
		||||
				// 若需要获取所有子节点,则codePathLike 使用default/type1|code1/type2|code2/去查。否则需要单独再去查一遍
 | 
			
		||||
				// 如用户分配了: "default/type1|code1/type2|code2/type3|code3/",即accountMathPath=default/type1|%/type2|%/type3/%/, 需要查询的codePathLike为: default/type1|%/type2|%/,即用户分配的标签路径是查询的子节点。
 | 
			
		||||
				// 则codePathLike 使用default/type1|code1/type2|code2/去查
 | 
			
		||||
				if strings.HasPrefix(accountMatchPath, codePathLike) {
 | 
			
		||||
					actualMatchCodePath := accountTagCodePathSections[len(entity.CodePath(codePathLike).GetPathSections())-1].Path
 | 
			
		||||
					needFilterAccountTagPaths[actualMatchCodePath] = append(needFilterAccountTagPaths[actualMatchCodePath], accountTag)
 | 
			
		||||
					if query.GetAllChildren {
 | 
			
		||||
					codePathLikes = append(codePathLikes, actualMatchCodePath)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 去重处理
 | 
			
		||||
		codePathLikes = collx.ArrayDeduplicate(codePathLikes)
 | 
			
		||||
@@ -444,19 +442,8 @@ func (p *tagTreeAppImpl) GetAccountTags(accountId uint64, query *entity.TagTreeQ
 | 
			
		||||
	tagResourceQuery.CodePathLikes = codePathLikes
 | 
			
		||||
	p.ListByQuery(tagResourceQuery, &tagResources)
 | 
			
		||||
 | 
			
		||||
	// 不是获取所有子节点,则需要额外查询需要过滤的节点信息。如用户分配了default/2|db_local/5|db_local_root/22|cWMpm6137g/标签,但是typePath为default/2|%/5|%/
 | 
			
		||||
	// 由于不是获取所有子节点,则会被追加Type进行过滤,故获取不到default/2|db_local/5|db_local_root/的信息,需要额外查询
 | 
			
		||||
	if !query.GetAllChildren && len(needFilterAccountTagPaths) > 0 {
 | 
			
		||||
		var otherTags []*dto.SimpleTagTree
 | 
			
		||||
		p.ListByQuery(&entity.TagTreeQuery{
 | 
			
		||||
			CodePaths: collx.MapKeys(needFilterAccountTagPaths),
 | 
			
		||||
		}, &otherTags)
 | 
			
		||||
		tagResources = append(tagResources, otherTags...)
 | 
			
		||||
		// 清空,因为不是获取所有子节点,so 后续不需要进行过滤
 | 
			
		||||
		clear(needFilterAccountTagPaths)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(needFilterAccountTagPaths) > 0 {
 | 
			
		||||
	// 获取所有子节点,并且存在需要过滤的路径,则进行过滤处理
 | 
			
		||||
	if query.GetAllChildren && len(needFilterAccountTagPaths) > 0 {
 | 
			
		||||
		tagResources = collx.ArrayFilter(tagResources, func(tr *dto.SimpleTagTree) bool {
 | 
			
		||||
			for codePathLike, accountTags := range needFilterAccountTagPaths {
 | 
			
		||||
				if strings.HasPrefix(tr.CodePath, codePathLike) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										75
									
								
								server/pkg/cache/cache.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										75
									
								
								server/pkg/cache/cache.go
									
									
									
									
										vendored
									
									
								
							@@ -1,25 +1,72 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"mayfly-go/pkg/utils/anyx"
 | 
			
		||||
	"mayfly-go/pkg/utils/jsonx"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/may-fly/cast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Cache interface {
 | 
			
		||||
	// 添加缓存,如果缓存则返回错误
 | 
			
		||||
	Add(k string, v any) error
 | 
			
		||||
	// Set 设置缓存值
 | 
			
		||||
	// duration == -1 则为永久缓存
 | 
			
		||||
	Set(key string, value any, duration time.Duration) error
 | 
			
		||||
 | 
			
		||||
	// 如果不存在则添加缓存值,否则直接返回
 | 
			
		||||
	AddIfAbsent(k string, v any)
 | 
			
		||||
	// Set2Str 将value转为字符串后设置缓存值
 | 
			
		||||
	Set2Str(key string, value any, duration time.Duration) error
 | 
			
		||||
 | 
			
		||||
	// 如果存在则直接返回,否则调用getValue回调函数获取值并添加该缓存值
 | 
			
		||||
	// @return 缓存值
 | 
			
		||||
	ComputeIfAbsent(k string, getValueFunc func(string) (any, error)) (any, error)
 | 
			
		||||
 | 
			
		||||
	// 获取缓存值,参数1为值,参数2->是否存在该缓存
 | 
			
		||||
	// Get 获取缓存值
 | 
			
		||||
	Get(k string) (any, bool)
 | 
			
		||||
 | 
			
		||||
	// 缓存数量
 | 
			
		||||
	// GetJson 获取json缓存值,并将其解析到指定的结构体指针
 | 
			
		||||
	GetJson(k string, valPtr any) bool
 | 
			
		||||
 | 
			
		||||
	// GetStr  获取字符串缓存值
 | 
			
		||||
	GetStr(k string) (string, bool)
 | 
			
		||||
 | 
			
		||||
	// GetInt  获取int缓存值
 | 
			
		||||
	GetInt(k string) (int, bool)
 | 
			
		||||
 | 
			
		||||
	// Delete 删除缓存
 | 
			
		||||
	Delete(key string) error
 | 
			
		||||
 | 
			
		||||
	// DeleteByKeyPrefix 根据key前缀删除缓存
 | 
			
		||||
	DeleteByKeyPrefix(keyPrefix string) error
 | 
			
		||||
 | 
			
		||||
	// Count 缓存数量
 | 
			
		||||
	Count() int
 | 
			
		||||
 | 
			
		||||
	// 删除缓存
 | 
			
		||||
	Delete(k string)
 | 
			
		||||
 | 
			
		||||
	// 清空所有缓存
 | 
			
		||||
	// Clear 清空所有缓存
 | 
			
		||||
	Clear()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type defaultCache struct {
 | 
			
		||||
	c Cache // 具体的缓存实现, 用于实现一些接口的通用方法
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dc *defaultCache) Set2Str(key string, value any, duration time.Duration) error {
 | 
			
		||||
	return dc.c.Set(key, anyx.ToString(value), duration)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dc *defaultCache) GetStr(k string) (string, bool) {
 | 
			
		||||
	if val, ok := dc.c.Get(k); ok {
 | 
			
		||||
		return cast.ToString(val), true
 | 
			
		||||
	}
 | 
			
		||||
	return "", false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dc *defaultCache) GetInt(k string) (int, bool) {
 | 
			
		||||
	if val, ok := dc.c.Get(k); ok {
 | 
			
		||||
		return cast.ToInt(val), true
 | 
			
		||||
	}
 | 
			
		||||
	return 0, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dc *defaultCache) GetJson(k string, valPtr any) bool {
 | 
			
		||||
	if val, ok := dc.GetStr(k); ok {
 | 
			
		||||
		jsonx.To(val, valPtr)
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								server/pkg/cache/global.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								server/pkg/cache/global.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"mayfly-go/pkg/rediscli"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var c Cache = NewLocalCache()
 | 
			
		||||
 | 
			
		||||
// SetCache 设置全局缓存实现
 | 
			
		||||
func SetCache(cache Cache) {
 | 
			
		||||
	c = cache
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetStr(key string) string {
 | 
			
		||||
	if val, ok := c.GetStr(key); ok {
 | 
			
		||||
		return val
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetInt(key string) int {
 | 
			
		||||
	if val, ok := c.GetInt(key); ok {
 | 
			
		||||
		return val
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get 获取缓存值,并使用json反序列化。返回是否获取成功。若不存在或者解析失败,则返回false
 | 
			
		||||
func Get[T any](key string, valPtr T) bool {
 | 
			
		||||
	return c.GetJson(key, valPtr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set 设置缓存值
 | 
			
		||||
func Set(key string, value any, duration time.Duration) error {
 | 
			
		||||
	return c.Set2Str(key, value, duration)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 删除指定key
 | 
			
		||||
func Del(key string) {
 | 
			
		||||
	c.Delete(key)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func UseRedisCache() bool {
 | 
			
		||||
	return rediscli.GetCli() != nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								server/pkg/cache/local.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								server/pkg/cache/local.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/may-fly/cast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type LocalCache struct {
 | 
			
		||||
	defaultCache
 | 
			
		||||
 | 
			
		||||
	tm *TimedCache
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ (Cache) = (*LocalCache)(nil)
 | 
			
		||||
 | 
			
		||||
func NewLocalCache() *LocalCache {
 | 
			
		||||
	lc := &LocalCache{
 | 
			
		||||
		tm: NewTimedCache(time.Minute*time.Duration(5), 30*time.Second),
 | 
			
		||||
	}
 | 
			
		||||
	lc.c = lc
 | 
			
		||||
	return lc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lc *LocalCache) Set(key string, value any, duration time.Duration) error {
 | 
			
		||||
	return lc.tm.Add(key, value, duration)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lc *LocalCache) Get(k string) (any, bool) {
 | 
			
		||||
	return lc.tm.Get(k)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lc *LocalCache) Delete(k string) error {
 | 
			
		||||
	lc.tm.Delete(k)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lc *LocalCache) DeleteByKeyPrefix(keyPrefix string) error {
 | 
			
		||||
	for key := range lc.tm.Items() {
 | 
			
		||||
		if strings.HasPrefix(cast.ToString(key), keyPrefix) {
 | 
			
		||||
			lc.tm.Delete(key)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lc *LocalCache) Count() int {
 | 
			
		||||
	return lc.tm.Count()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (lc *LocalCache) Clear() {
 | 
			
		||||
	lc.tm.Clear()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								server/pkg/cache/redis.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								server/pkg/cache/redis.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"mayfly-go/pkg/utils/anyx"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/redis/go-redis/v9"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type RedisCache struct {
 | 
			
		||||
	defaultCache
 | 
			
		||||
 | 
			
		||||
	redisCli *redis.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ (Cache) = (*RedisCache)(nil)
 | 
			
		||||
 | 
			
		||||
func NewRedisCache(rc *redis.Client) *RedisCache {
 | 
			
		||||
	rcache := &RedisCache{
 | 
			
		||||
		redisCli: rc,
 | 
			
		||||
	}
 | 
			
		||||
	rcache.c = rcache
 | 
			
		||||
	return rcache
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ (Cache) = (*RedisCache)(nil)
 | 
			
		||||
 | 
			
		||||
func (rc *RedisCache) Set(key string, value any, duration time.Duration) error {
 | 
			
		||||
	if _, ok := value.(string); !ok {
 | 
			
		||||
		return errors.New("redis cache set err -> value must be string")
 | 
			
		||||
	}
 | 
			
		||||
	return rc.redisCli.Set(context.Background(), key, anyx.ToString(value), duration).Err()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rc *RedisCache) Get(k string) (any, bool) {
 | 
			
		||||
	if val, err := rc.redisCli.Get(context.Background(), k).Result(); err != nil {
 | 
			
		||||
		return "", false
 | 
			
		||||
	} else {
 | 
			
		||||
		return val, true
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rc *RedisCache) Delete(k string) error {
 | 
			
		||||
	return rc.redisCli.Del(context.Background(), k).Err()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rc *RedisCache) DeleteByKeyPrefix(keyPrefix string) error {
 | 
			
		||||
	res, err := rc.redisCli.Keys(context.TODO(), keyPrefix+"*").Result()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	for _, key := range res {
 | 
			
		||||
		Del(key)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rc *RedisCache) Count() int {
 | 
			
		||||
	return int(rc.redisCli.DBSize(context.Background()).Val())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rc *RedisCache) Clear() {
 | 
			
		||||
	rc.redisCli.FlushDB(context.Background())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										105
									
								
								server/pkg/cache/str_cache.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										105
									
								
								server/pkg/cache/str_cache.go
									
									
									
									
										vendored
									
									
								
							@@ -1,105 +0,0 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"mayfly-go/pkg/logx"
 | 
			
		||||
	"mayfly-go/pkg/rediscli"
 | 
			
		||||
	"mayfly-go/pkg/utils/anyx"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/may-fly/cast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var tm *TimedCache
 | 
			
		||||
 | 
			
		||||
// 如果系统有设置redis信息,则从redis获取,否则本机内存获取
 | 
			
		||||
func GetStr(key string) string {
 | 
			
		||||
	if !UseRedisCache() {
 | 
			
		||||
		checkCache()
 | 
			
		||||
		val, _ := tm.Get(key)
 | 
			
		||||
		if val == nil {
 | 
			
		||||
			return ""
 | 
			
		||||
		}
 | 
			
		||||
		return cast.ToString(val)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if res, err := rediscli.Get(key); err == nil {
 | 
			
		||||
		return res
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetInt(key string) int {
 | 
			
		||||
	val := GetStr(key)
 | 
			
		||||
	if val == "" {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return cast.ToInt(key)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get 获取缓存值,并使用json反序列化。返回是否获取成功。若不存在或者解析失败,则返回false
 | 
			
		||||
func Get[T any](key string, valPtr T) bool {
 | 
			
		||||
	strVal := GetStr(key)
 | 
			
		||||
	if strVal == "" {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if err := json.Unmarshal([]byte(strVal), valPtr); err != nil {
 | 
			
		||||
		logx.Errorf("json转换缓存中的值失败: %v", err)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetStr 如果系统有设置redis信息,则使用redis存,否则存于本机内存。duration == -1则为永久缓存
 | 
			
		||||
func SetStr(key, value string, duration time.Duration) error {
 | 
			
		||||
	if !UseRedisCache() {
 | 
			
		||||
		checkCache()
 | 
			
		||||
		return tm.Add(key, value, duration)
 | 
			
		||||
	}
 | 
			
		||||
	return rediscli.Set(key, value, duration)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set 如果系统有设置redis信息,则使用redis存,否则存于本机内存。duration == -1则为永久缓存
 | 
			
		||||
func Set(key string, value any, duration time.Duration) error {
 | 
			
		||||
	strVal := anyx.ToString(value)
 | 
			
		||||
	if !UseRedisCache() {
 | 
			
		||||
		checkCache()
 | 
			
		||||
		return tm.Add(key, strVal, duration)
 | 
			
		||||
	}
 | 
			
		||||
	return rediscli.Set(key, strVal, duration)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 删除指定key
 | 
			
		||||
func Del(key string) {
 | 
			
		||||
	if !UseRedisCache() {
 | 
			
		||||
		checkCache()
 | 
			
		||||
		tm.Delete(key)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	rediscli.Del(key)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DelByKeyPrefix 根据key前缀删除满足前缀的所有缓存
 | 
			
		||||
func DelByKeyPrefix(keyPrefix string) error {
 | 
			
		||||
	if !UseRedisCache() {
 | 
			
		||||
		checkCache()
 | 
			
		||||
		for key := range tm.Items() {
 | 
			
		||||
			if strings.HasPrefix(cast.ToString(key), keyPrefix) {
 | 
			
		||||
				tm.Delete(key)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return rediscli.DelByKeyPrefix(keyPrefix)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func UseRedisCache() bool {
 | 
			
		||||
	return rediscli.GetCli() != nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checkCache() {
 | 
			
		||||
	if tm == nil {
 | 
			
		||||
		tm = NewTimedCache(time.Minute*time.Duration(5), 30*time.Second)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -12,10 +12,6 @@ import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"mayfly-go/pkg/cache"
 | 
			
		||||
	"mayfly-go/pkg/logx"
 | 
			
		||||
	"mayfly-go/pkg/model"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/crypto/bcrypt"
 | 
			
		||||
)
 | 
			
		||||
@@ -106,119 +102,6 @@ func RsaDecrypt(privateKeyStr string, data []byte) ([]byte, error) {
 | 
			
		||||
	return rsa.DecryptPKCS1v15(rand.Reader, priv, data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 使用系统默认的私钥解密
 | 
			
		||||
// @param base64 字符串是否使用base64编码
 | 
			
		||||
func DefaultRsaDecrypt(data string, useBase64 bool) (string, error) {
 | 
			
		||||
	// 空字符串不解密
 | 
			
		||||
	if data == "" {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
	if useBase64 {
 | 
			
		||||
		if decodeBase64, err := base64.StdEncoding.DecodeString(data); err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		} else {
 | 
			
		||||
			data = string(decodeBase64)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	priKey, err := GetRsaPrivateKey()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	val, err := RsaDecrypt(priKey, []byte(data))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return string(val), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// 公钥文件路径
 | 
			
		||||
	publicKeyFile = "./mayfly_rsa.pub"
 | 
			
		||||
	// 私钥文件路径
 | 
			
		||||
	privateKeyFile = "./mayfly_rsa"
 | 
			
		||||
 | 
			
		||||
	publicKeyK  = "mayfly:public-key"
 | 
			
		||||
	privateKeyK = "mayfly:private-key"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 获取系统的RSA公钥
 | 
			
		||||
func GetRsaPublicKey() (string, error) {
 | 
			
		||||
	if cache.UseRedisCache() {
 | 
			
		||||
		publicKey := cache.GetStr(publicKeyK)
 | 
			
		||||
		if publicKey != "" {
 | 
			
		||||
			return publicKey, nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		content, err := os.ReadFile(publicKeyFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			publicKey := cache.GetStr(publicKeyK)
 | 
			
		||||
			if publicKey != "" {
 | 
			
		||||
				return publicKey, nil
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			return string(content), nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, pubKey, err := GenerateAndSaveRSAKey()
 | 
			
		||||
	return pubKey, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 获取系统私钥
 | 
			
		||||
func GetRsaPrivateKey() (string, error) {
 | 
			
		||||
	if cache.UseRedisCache() {
 | 
			
		||||
		priKey := cache.GetStr(privateKeyK)
 | 
			
		||||
		if priKey != "" {
 | 
			
		||||
			return priKey, nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		content, err := os.ReadFile(privateKeyFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			priKey := cache.GetStr(privateKeyK)
 | 
			
		||||
			if priKey != "" {
 | 
			
		||||
				return priKey, nil
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			return string(content), nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	priKey, _, err := GenerateAndSaveRSAKey()
 | 
			
		||||
	return priKey, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 生成并保存rsa key,优先保存于磁盘,若磁盘保存失败,则保存至缓存
 | 
			
		||||
//
 | 
			
		||||
// 依次返回 privateKey, publicKey, error
 | 
			
		||||
func GenerateAndSaveRSAKey() (string, string, error) {
 | 
			
		||||
	privateKey, publicKey, err := GenerateRSAKey(1024)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 如果使用了redis缓存,则优先存入redis
 | 
			
		||||
	if cache.UseRedisCache() {
 | 
			
		||||
		logx.Debug("系统配置了redis, rsa存入redis")
 | 
			
		||||
		cache.SetStr(privateKeyK, privateKey, -1)
 | 
			
		||||
		cache.SetStr(publicKeyK, publicKey, -1)
 | 
			
		||||
		return privateKey, publicKey, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = os.WriteFile(privateKeyFile, []byte(privateKey), 0644)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logx.ErrorTrace("RSA私钥写入磁盘文件失败, 使用缓存存储该私钥", err)
 | 
			
		||||
		cache.SetStr(privateKeyK, privateKey, -1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = os.WriteFile(publicKeyFile, []byte(publicKey), 0644)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logx.ErrorTrace("RSA公钥写入磁盘文件失败, 使用缓存存储该公钥", err)
 | 
			
		||||
		cache.SetStr(publicKeyK, publicKey, -1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return privateKey, publicKey, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AesEncrypt 加密
 | 
			
		||||
func AesEncrypt(data []byte, key []byte) ([]byte, error) {
 | 
			
		||||
	//创建加密实例
 | 
			
		||||
@@ -281,12 +164,6 @@ func AesDecryptBase64(data string, key []byte) ([]byte, error) {
 | 
			
		||||
	return AesDecrypt(dataByte, key)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AesDecryptByLa(data string, la *model.LoginAccount) (string, error) {
 | 
			
		||||
	key := []byte(la.GetAesKey())
 | 
			
		||||
	res, err := AesDecryptBase64(data, key)
 | 
			
		||||
	return string(res), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// pkcs7Padding 填充
 | 
			
		||||
func pkcs7Padding(data []byte, blockSize int) []byte {
 | 
			
		||||
	//判断缺少几位长度。最少1,最多 blockSize
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user