refactor: code optimization

This commit is contained in:
meilin.huang
2025-04-23 20:36:32 +08:00
parent 798ab7d18b
commit 2170509d92
33 changed files with 445 additions and 380 deletions

View File

@@ -56,11 +56,11 @@
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"code-inspector-plugin": "^0.20.9", "code-inspector-plugin": "^0.20.9",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"eslint": "^9.24.0", "eslint": "^9.25.1",
"eslint-plugin-vue": "^10.0.0", "eslint-plugin-vue": "^10.0.0",
"postcss": "^8.5.3", "postcss": "^8.5.3",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"sass": "^1.86.3", "sass": "^1.87.0",
"tailwindcss": "^4.1.4", "tailwindcss": "^4.1.4",
"typescript": "^5.8.2", "typescript": "^5.8.2",
"vite": "^6.3.2", "vite": "^6.3.2",

View File

@@ -1,6 +1,6 @@
<template> <template>
<el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n"> <el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
<div class="!h-full"> <div class="h-full">
<el-watermark <el-watermark
:zIndex="10000000" :zIndex="10000000"
:width="210" :width="210"

View File

@@ -1,7 +1,7 @@
<template> <template>
<el-container class="layout-container flex-center"> <el-container class="layout-container flex-center">
<Header /> <Header />
<el-container class="layout-mian-height-50"> <el-container class="h-[calc(100vh-50px)]">
<Aside /> <Aside />
<div class="flex-center layout-backtop"> <div class="flex-center layout-backtop">
<TagsView v-if="themeConfig.isTagsview" /> <TagsView v-if="themeConfig.isTagsview" />

View File

@@ -5,10 +5,8 @@
<Aside /> <Aside />
<el-container class="flex-center layout-backtop"> <el-container class="flex-center layout-backtop">
<Header v-if="isFixedHeader" /> <Header v-if="isFixedHeader" />
<!-- <el-scrollbar> -->
<Header v-if="!isFixedHeader" /> <Header v-if="!isFixedHeader" />
<Main /> <Main />
<!-- </el-scrollbar> -->
</el-container> </el-container>
</div> </div>
<el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop> <el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>

View File

@@ -3,10 +3,8 @@
<Aside /> <Aside />
<el-container class="flex-center layout-backtop"> <el-container class="flex-center layout-backtop">
<Header v-if="isFixedHeader" /> <Header v-if="isFixedHeader" />
<!-- <el-scrollbar view-class="!h-full" ref="layoutDefaultsScrollbarRef"> -->
<Header v-if="!isFixedHeader" /> <Header v-if="!isFixedHeader" />
<Main /> <Main />
<!-- </el-scrollbar> -->
</el-container> </el-container>
<el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop> <el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>
</el-container> </el-container>

View File

@@ -34,13 +34,14 @@ body,
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
background-color: var(--bg-main-color); background-color: var(--bg-main-color);
font-size: 14px; font-size: 14px;
overflow: hidden; // overflow: hidden;
position: relative; // position: relative;
} }
/* 主布局样式 /* 主布局样式
------------------------------- */ ------------------------------- */
.layout-container { .layout-container {
display: flex;
width: 100%; width: 100%;
height: 100%; height: 100%;
@@ -102,10 +103,6 @@ body,
transition: width 0.3s ease; transition: width 0.3s ease;
} }
.layout-mian-height-50 {
height: calc(100vh - 50px);
}
.layout-columns-warp { .layout-columns-warp {
flex: 1; flex: 1;
display: flex; display: flex;
@@ -259,16 +256,6 @@ body,
opacity: 0; 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 */ /* custom card */
.card { .card {

View File

@@ -7,13 +7,13 @@
</template> </template>
<template #default="scope"> <template #default="scope">
<el-button v-auth="'authcert:save'" @click="edit(scope.row, scope.$index)" type="primary" icon="edit" link></el-button> <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 <el-button
:title="$t('ac.testConn')" :title="$t('ac.testConn')"
:loading="props.testConnBtnLoading && scope.$index == state.idx" :loading="props.testConnBtnLoading && scope.$index == state.idx"
:disabled="props.testConnBtnLoading" :disabled="props.testConnBtnLoading"
class="ml-0.5" class="!ml-0.5"
type="success" type="success"
@click="testConn(scope.row, scope.$index)" @click="testConn(scope.row, scope.$index)"
icon="Link" icon="Link"

View File

@@ -22,8 +22,8 @@
<span <span
:id="node.key" :id="node.key"
@dblclick="treeNodeDblclick(data, node)" @dblclick="treeNodeDblclick(data, node)"
class="node-container flex items-center w-full cursor-pointer none-select" class="node-container flex items-center w-full cursor-pointer select-none"
:class="data.type.nodeDblclickFunc ? 'none-select' : ''" :class="data.type.nodeDblclickFunc ? 'select-none' : ''"
> >
<span v-if="data.type.value == TagTreeNode.TagPath"> <span v-if="data.type.value == TagTreeNode.TagPath">
<tag-info :tag-path="data.label" /> <tag-info :tag-path="data.label" />

View File

@@ -324,7 +324,7 @@ const columns = [
TableColumn.new('fs', 'machine.fs').isSlot().setAddWidth(25), TableColumn.new('fs', 'machine.fs').isSlot().setAddWidth(25),
TableColumn.new('remark', 'common.remark'), TableColumn.new('remark', 'common.remark'),
TableColumn.new('code', 'common.code'), 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无效 // 该用户拥有的的操作列按钮权限使用v-if进行判断v-auth对el-dropdown-item无效

View File

@@ -1,17 +1,19 @@
<template> <template>
<div class="tag-tree-list card"> <div class="tag-tree-list card h-full flex">
<Splitpanes class="default-theme"> <Splitpanes class="default-theme">
<Pane size="30" min-size="25" max-size="35"> <Pane size="30" min-size="25" max-size="35" class="flex flex-col flex-1">
<div class="card !p-1 !mb-1 !mr-1"> <div class="card !p-1 !mb-1 !mr-1 flex justify-between">
<el-input v-model="filterTag" clearable :placeholder="$t('tag.nameFilterPlaceholder')" style="width: 200px; margin-right: 10px" /> <div class="mb-1">
<el-button <el-input v-model="filterTag" clearable :placeholder="$t('tag.nameFilterPlaceholder')" class="mr-2 !w-[200px]" />
v-if="useUserInfo().userInfo.username == 'admin'" <el-button
v-auth="'tag:save'" v-if="useUserInfo().userInfo.username == 'admin'"
type="primary" v-auth="'tag:save'"
icon="plus" type="primary"
@click="showSaveTagDialog(null)" icon="plus"
></el-button> @click="showSaveTagDialog(null)"
<div class="float-right"> ></el-button>
</div>
<div>
<el-tooltip placement="top"> <el-tooltip placement="top">
<template #content> <template #content>
{{ $t('tag.tagTips1') }} {{ $t('tag.tagTips1') }}
@@ -19,11 +21,7 @@
{{ $t('tag.tagTips2') }} <br /> {{ $t('tag.tagTips2') }} <br />
{{ $t('tag.tagTips3') }} {{ $t('tag.tagTips3') }}
</template> </template>
<span> <SvgIcon name="question-filled" />
<el-icon>
<question-filled />
</el-icon>
</span>
</el-tooltip> </el-tooltip>
</div> </div>
</div> </div>
@@ -67,8 +65,8 @@
</Pane> </Pane>
<Pane min-size="40" size="70"> <Pane min-size="40" size="70">
<div class="ml-2"> <div class="ml-2 h-full">
<el-tabs @tab-change="tabChange" v-model="state.activeTabName" v-if="currentTag"> <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-tab-pane :label="$t('common.detail')" :name="TagDetail">
<el-descriptions :column="2" border> <el-descriptions :column="2" border>
<el-descriptions-item :label="$t('common.type')"> <el-descriptions-item :label="$t('common.type')">
@@ -91,6 +89,7 @@
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane
class="h-full"
:disabled="currentTag.type != TagResourceTypeEnum.Tag.value" :disabled="currentTag.type != TagResourceTypeEnum.Tag.value"
:label="`${$t('tag.machine')} (${resourceCount.machine || 0})`" :label="`${$t('tag.machine')} (${resourceCount.machine || 0})`"
:name="MachineTag" :name="MachineTag"
@@ -99,6 +98,7 @@
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane
class="h-full"
:disabled="currentTag.type != TagResourceTypeEnum.Tag.value" :disabled="currentTag.type != TagResourceTypeEnum.Tag.value"
:label="`${$t('tag.db')} (${resourceCount.db || 0})`" :label="`${$t('tag.db')} (${resourceCount.db || 0})`"
:name="DbTag" :name="DbTag"
@@ -107,6 +107,7 @@
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane
class="h-full"
:disabled="currentTag.type != TagResourceTypeEnum.Tag.value" :disabled="currentTag.type != TagResourceTypeEnum.Tag.value"
:label="`Redis (${resourceCount.redis || 0})`" :label="`Redis (${resourceCount.redis || 0})`"
:name="RedisTag" :name="RedisTag"
@@ -115,6 +116,7 @@
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane
class="h-full"
:disabled="currentTag.type != TagResourceTypeEnum.Tag.value" :disabled="currentTag.type != TagResourceTypeEnum.Tag.value"
:label="`Mongo (${resourceCount.mongo || 0})`" :label="`Mongo (${resourceCount.mongo || 0})`"
:name="MongoTag" :name="MongoTag"
@@ -490,17 +492,10 @@ const removeDeafultExpandId = (id: any) => {
<style lang="scss"> <style lang="scss">
.tag-tree-list { .tag-tree-list {
.tag-tree-data { .tag-tree-data {
height: calc(100vh - 202px);
.el-tree-node__content { .el-tree-node__content {
height: 40px; height: 40px;
line-height: 40px; line-height: 40px;
} }
} }
.el-tree {
display: inline-block;
min-width: 100%;
}
} }
</style> </style>

View File

@@ -1,24 +1,23 @@
<template> <template>
<div class="card system-resouce-list"> <div class="card system-resource-list h-full flex">
<Splitpanes class="default-theme"> <Splitpanes class="default-theme">
<Pane size="25" min-size="20" max-size="30"> <Pane size="30" min-size="25" max-size="35" class="flex flex-col flex-1">
<div class="card !p-1 mr-1"> <div class="card !p-1 mr-1 flex justify-between">
<el-input v-model="filterResource" clearable :placeholder="$t('system.menu.filterPlaceholder')" style="width: 200px; margin-right: 10px" /> <div class="mb-1">
<el-button v-auth="perms.addResource" type="primary" icon="plus" @click="addResource(false)"></el-button> <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"> <el-tooltip placement="top">
<template #content> {{ $t('system.menu.opTips') }} </template> <template #content> {{ $t('system.menu.opTips') }} </template>
<span> <SvgIcon name="question-filled" />
<SvgIcon name="question-filled" />
</span>
</el-tooltip> </el-tooltip>
</div> </div>
</div> </div>
<el-scrollbar class="tree-data"> <el-scrollbar>
<el-tree <el-tree
ref="resourceTreeRef" ref="resourceTreeRef"
class="none-select"
:indent="24" :indent="24"
node-key="id" node-key="id"
:props="props" :props="props"
@@ -62,7 +61,7 @@
</el-scrollbar> </el-scrollbar>
</Pane> </Pane>
<Pane min-size="40"> <Pane min-size="40" size="70">
<div class="ml-2"> <div class="ml-2">
<el-tabs v-model="state.activeTabName" @tab-click="onTabClick" v-if="currentResource"> <el-tabs v-model="state.activeTabName" @tab-click="onTabClick" v-if="currentResource">
<el-tab-pane :label="$t('common.detail')" :name="ResourceDetail"> <el-tab-pane :label="$t('common.detail')" :name="ResourceDetail">
@@ -437,29 +436,10 @@ const removeDeafultExpandId = (id: any) => {
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
.system-resouce-list { .system-resource-list {
.el-tree-node__content { .el-tree-node__content {
height: 40px; height: 40px;
line-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> </style>

View File

@@ -28,7 +28,7 @@ func AddInitFunc(initFunc InitFunc) {
// 系统启动时,调用各个模块的初始化函数 // 系统启动时,调用各个模块的初始化函数
func InitOther() { func InitOther() {
// 调用各个默认ioc组件注册初始化优先调用ioc初始化注册函数和注入函数可能在后续的InitFunc中需要用到依赖实例 // 调用各个模块ioc组件注册初始化优先调用ioc初始化注册函数和注入函数可能在后续的InitFunc中需要用到依赖实例
for _, initIocFunc := range initIocFuncs { for _, initIocFunc := range initIocFuncs {
initIocFunc() initIocFunc()
} }

View File

@@ -7,7 +7,7 @@ var (
terminateFuncs = make([]TerminateFunc, 0) terminateFuncs = make([]TerminateFunc, 0)
) )
// 添加系统退出终止时执行的函数,由各个默认自行添加 // 添加系统退出终止时执行的函数,由各个模块自行添加
func AddTerminateFunc(terminateFunc TerminateFunc) { func AddTerminateFunc(terminateFunc TerminateFunc) {
terminateFuncs = append(terminateFuncs, terminateFunc) terminateFuncs = append(terminateFuncs, terminateFunc)
} }

View File

@@ -8,6 +8,7 @@ import (
"mayfly-go/internal/auth/imsg" "mayfly-go/internal/auth/imsg"
"mayfly-go/internal/auth/pkg/captcha" "mayfly-go/internal/auth/pkg/captcha"
"mayfly-go/internal/auth/pkg/otp" "mayfly-go/internal/auth/pkg/otp"
"mayfly-go/internal/pkg/utils"
sysapp "mayfly-go/internal/sys/application" sysapp "mayfly-go/internal/sys/application"
sysentity "mayfly-go/internal/sys/domain/entity" sysentity "mayfly-go/internal/sys/domain/entity"
"mayfly-go/pkg/biz" "mayfly-go/pkg/biz"
@@ -18,7 +19,6 @@ import (
"mayfly-go/pkg/utils/collx" "mayfly-go/pkg/utils/collx"
"mayfly-go/pkg/utils/cryptox" "mayfly-go/pkg/utils/cryptox"
"mayfly-go/pkg/ws" "mayfly-go/pkg/ws"
"strconv"
"time" "time"
) )
@@ -62,7 +62,7 @@ func (a *AccountLogin) Login(rc *req.Ctx) {
clientIp := getIpAndRegion(rc) clientIp := getIpAndRegion(rc)
rc.ReqParam = collx.Kvs("username", username, "ip", clientIp) 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") biz.ErrIsNilAppendErr(err, "decryption password error: %s")
account := &sysentity.Account{Username: username} account := &sysentity.Account{Username: username}
@@ -76,7 +76,7 @@ func (a *AccountLogin) Login(rc *req.Ctx) {
if err != nil || !cryptox.CheckPwdHash(originPwd, account.Password) { if err != nil || !cryptox.CheckPwdHash(originPwd, account.Password) {
nowFailCount++ 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)) panic(errorx.NewBizI(ctx, imsg.ErrLoginFail, "failCount", nowFailCount))
} }
@@ -115,7 +115,7 @@ func (a *AccountLogin) OtpVerify(rc *req.Ctx) {
otpSecret := otpInfo.OtpSecret otpSecret := otpInfo.OtpSecret
if !otp.Validate(otpVerify.Code, 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)) panic(errorx.NewBizI(ctx, imsg.ErrOtpCheckFail))
} }

View File

@@ -15,7 +15,6 @@ import (
"mayfly-go/pkg/i18n" "mayfly-go/pkg/i18n"
"mayfly-go/pkg/req" "mayfly-go/pkg/req"
"mayfly-go/pkg/utils/collx" "mayfly-go/pkg/utils/collx"
"mayfly-go/pkg/utils/jsonx"
"mayfly-go/pkg/utils/netx" "mayfly-go/pkg/utils/netx"
"mayfly-go/pkg/utils/stringx" "mayfly-go/pkg/utils/stringx"
"mayfly-go/pkg/utils/timex" "mayfly-go/pkg/utils/timex"
@@ -95,7 +94,7 @@ func useOtp(account *sysentity.Account, otpIssuer, accessToken string, refreshTo
AccessToken: accessToken, AccessToken: accessToken,
RefreshToken: refreshToken, 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 return otpInfo, otpUrl, token
} }

View File

@@ -8,6 +8,7 @@ import (
"mayfly-go/internal/auth/config" "mayfly-go/internal/auth/config"
"mayfly-go/internal/auth/imsg" "mayfly-go/internal/auth/imsg"
"mayfly-go/internal/auth/pkg/captcha" "mayfly-go/internal/auth/pkg/captcha"
"mayfly-go/internal/pkg/utils"
sysapp "mayfly-go/internal/sys/application" sysapp "mayfly-go/internal/sys/application"
sysentity "mayfly-go/internal/sys/domain/entity" sysentity "mayfly-go/internal/sys/domain/entity"
"mayfly-go/pkg/biz" "mayfly-go/pkg/biz"
@@ -17,7 +18,6 @@ import (
"mayfly-go/pkg/req" "mayfly-go/pkg/req"
"mayfly-go/pkg/utils/collx" "mayfly-go/pkg/utils/collx"
"mayfly-go/pkg/utils/cryptox" "mayfly-go/pkg/utils/cryptox"
"strconv"
"strings" "strings"
"time" "time"
@@ -61,7 +61,7 @@ func (a *LdapLogin) Login(rc *req.Ctx) {
clientIp := getIpAndRegion(rc) clientIp := getIpAndRegion(rc)
rc.ReqParam = collx.Kvs("username", username, "ip", clientIp) 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") biz.ErrIsNilAppendErr(err, "decryption password error: %s")
// LDAP 用户本地密码为空,不允许本地登录 // LDAP 用户本地密码为空,不允许本地登录
biz.NotEmpty(originPwd, "password cannot be empty") biz.NotEmpty(originPwd, "password cannot be empty")
@@ -78,7 +78,7 @@ func (a *LdapLogin) Login(rc *req.Ctx) {
if err != nil { if err != nil {
nowFailCount++ 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)) panic(errorx.NewBizI(ctx, imsg.ErrLoginFail, "failCount", nowFailCount))
} }

View File

@@ -55,14 +55,14 @@ func (o *Oauth2Login) ReqConfs() *req.Confs {
func (a *Oauth2Login) OAuth2Login(rc *req.Ctx) { func (a *Oauth2Login) OAuth2Login(rc *req.Ctx) {
client, _ := a.getOAuthClient() client, _ := a.getOAuthClient()
state := stringx.Rand(32) 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)) rc.Redirect(http.StatusFound, client.AuthCodeURL(state))
} }
func (a *Oauth2Login) OAuth2Bind(rc *req.Ctx) { func (a *Oauth2Login) OAuth2Bind(rc *req.Ctx) {
client, _ := a.getOAuthClient() client, _ := a.getOAuthClient()
state := stringx.Rand(32) 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) 5*time.Minute)
rc.Redirect(http.StatusFound, client.AuthCodeURL(state)) rc.Redirect(http.StatusFound, client.AuthCodeURL(state))
} }

View File

@@ -1,9 +1,9 @@
package api package api
import ( import (
"mayfly-go/internal/pkg/utils"
"mayfly-go/pkg/biz" "mayfly-go/pkg/biz"
"mayfly-go/pkg/req" "mayfly-go/pkg/req"
"mayfly-go/pkg/utils/cryptox"
) )
type Common struct { type Common struct {
@@ -19,7 +19,7 @@ func (c *Common) ReqConfs() *req.Confs {
} }
func (i *Common) RasPublicKey(rc *req.Ctx) { func (i *Common) RasPublicKey(rc *req.Ctx) {
publicKeyStr, err := cryptox.GetRsaPublicKey() publicKeyStr, err := utils.GetRsaPublicKey()
biz.ErrIsNilAppendErr(err, "rsa - failed to genenrate public key") biz.ErrIsNilAppendErr(err, "rsa - failed to genenrate public key")
rc.ResData = publicKeyStr rc.ResData = publicKeyStr
} }

View File

@@ -14,6 +14,7 @@ import (
"mayfly-go/internal/event" "mayfly-go/internal/event"
msgapp "mayfly-go/internal/msg/application" msgapp "mayfly-go/internal/msg/application"
msgdto "mayfly-go/internal/msg/application/dto" msgdto "mayfly-go/internal/msg/application/dto"
"mayfly-go/internal/pkg/utils"
tagapp "mayfly-go/internal/tag/application" tagapp "mayfly-go/internal/tag/application"
tagentity "mayfly-go/internal/tag/domain/entity" tagentity "mayfly-go/internal/tag/domain/entity"
"mayfly-go/pkg/biz" "mayfly-go/pkg/biz"
@@ -24,7 +25,6 @@ import (
"mayfly-go/pkg/req" "mayfly-go/pkg/req"
"mayfly-go/pkg/utils/anyx" "mayfly-go/pkg/utils/anyx"
"mayfly-go/pkg/utils/collx" "mayfly-go/pkg/utils/collx"
"mayfly-go/pkg/utils/cryptox"
"mayfly-go/pkg/utils/writerx" "mayfly-go/pkg/utils/writerx"
"strings" "strings"
"time" "time"
@@ -144,7 +144,7 @@ func (d *Db) ExecSql(rc *req.Ctx) {
biz.ErrIsNilAppendErr(d.tagApp.CanAccess(rc.GetLoginAccount().Id, dbConn.Info.CodePath...), "%s") biz.ErrIsNilAppendErr(d.tagApp.CanAccess(rc.GetLoginAccount().Id, dbConn.Info.CodePath...), "%s")
global.EventBus.Publish(rc.MetaCtx, event.EventTopicResourceOp, dbConn.Info.CodePath[0]) 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") biz.ErrIsNilAppendErr(err, "sql decoding failure: %s")
rc.ReqParam = fmt.Sprintf("%s %s\n-> %s", dbConn.Info.GetLogDesc(), form.ExecId, sqlStr) rc.ReqParam = fmt.Sprintf("%s %s\n-> %s", dbConn.Info.GetLogDesc(), form.ExecId, sqlStr)

View File

@@ -6,9 +6,9 @@ import (
"mayfly-go/internal/db/application" "mayfly-go/internal/db/application"
"mayfly-go/internal/db/domain/entity" "mayfly-go/internal/db/domain/entity"
"mayfly-go/internal/db/imsg" "mayfly-go/internal/db/imsg"
"mayfly-go/internal/pkg/utils"
"mayfly-go/pkg/biz" "mayfly-go/pkg/biz"
"mayfly-go/pkg/req" "mayfly-go/pkg/req"
"mayfly-go/pkg/utils/cryptox"
"mayfly-go/pkg/utils/stringx" "mayfly-go/pkg/utils/stringx"
"strings" "strings"
@@ -67,7 +67,7 @@ func (d *DataSyncTask) SaveTask(rc *req.Ctx) {
task := req.BindJsonAndCopyTo[*entity.DataSyncTask](rc, form, new(entity.DataSyncTask)) task := req.BindJsonAndCopyTo[*entity.DataSyncTask](rc, form, new(entity.DataSyncTask))
// 解码base64 sql // 解码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") biz.ErrIsNilAppendErr(err, "sql decoding failure: %s")
sql := stringx.TrimSpaceAndBr(sqlStr) sql := stringx.TrimSpaceAndBr(sqlStr)
task.DataSql = sql task.DataSql = sql

View File

@@ -12,7 +12,7 @@ import (
const MachineStatCacheKey = "mayfly:machine:%d:stat" const MachineStatCacheKey = "mayfly:machine:%d:stat"
func SaveMachineStats(machineId uint64, stat *mcm.Stats) error { 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) { func GetMachineStats(machineId uint64) (*mcm.Stats, error) {

View File

@@ -4,14 +4,25 @@ import (
"context" "context"
"fmt" "fmt"
"mayfly-go/internal/pkg/config" "mayfly-go/internal/pkg/config"
"mayfly-go/pkg/cache"
"mayfly-go/pkg/logx" "mayfly-go/pkg/logx"
"mayfly-go/pkg/rediscli" "mayfly-go/pkg/rediscli"
"github.com/redis/go-redis/v9" "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()) rediscli.SetCli(connRedis())
cache.SetCache(cache.NewRedisCache(redisCli))
} }
func connRedis() *redis.Client { func connRedis() *redis.Client {
@@ -21,7 +32,7 @@ func connRedis() *redis.Client {
// logx.Panic("未找到redis配置信息") // logx.Panic("未找到redis配置信息")
return nil 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{ rdb := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%d", redisConf.Host, redisConf.Port), Addr: fmt.Sprintf("%s:%d", redisConf.Host, redisConf.Port),
Password: redisConf.Password, // no password set Password: redisConf.Password, // no password set
@@ -30,7 +41,7 @@ func connRedis() *redis.Client {
// 测试连接 // 测试连接
_, e := rdb.Ping(context.TODO()).Result() _, e := rdb.Ping(context.TODO()).Result()
if e != nil { 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 return rdb
} }

View File

@@ -33,8 +33,8 @@ func RunWebServer() {
// 初始化并赋值数据库全局变量 // 初始化并赋值数据库全局变量
initDb() initDb()
// 有配置redis信息则初始化redis。多台机器部署需要使用redis存储验证码、权限、公私钥等 // 初始化缓存
initRedis() initCache()
// 数据库升级操作 // 数据库升级操作
if err := migration.RunMigrations(global.Db); err != nil { if err := migration.RunMigrations(global.Db); err != nil {

View 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
}

View File

@@ -110,7 +110,7 @@ func (a *Account) ChangePassword(rc *req.Ctx) {
form := req.BindJsonAndValid(rc, new(form.AccountChangePasswordForm)) 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") biz.ErrIsNilAppendErr(err, "Wrong to decrypt old password: %s")
account := &entity.Account{Username: form.Username} 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.IsTrueI(ctx, cryptox.CheckPwdHash(originOldPwd, account.Password), imsg.ErrOldPasswordWrong)
biz.IsTrue(account.IsEnable(), "This account is not available") 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.ErrIsNilAppendErr(err, "Wrong to decrypt new password: %s")
biz.IsTrueI(ctx, utils.CheckAccountPasswordLever(originNewPwd), imsg.ErrAccountPasswordNotFollowRule) biz.IsTrueI(ctx, utils.CheckAccountPasswordLever(originNewPwd), imsg.ErrAccountPasswordNotFollowRule)

View File

@@ -2,7 +2,6 @@ package application
import ( import (
"context" "context"
"encoding/json"
"mayfly-go/internal/sys/domain/entity" "mayfly-go/internal/sys/domain/entity"
"mayfly-go/internal/sys/domain/repository" "mayfly-go/internal/sys/domain/repository"
"mayfly-go/pkg/base" "mayfly-go/pkg/base"
@@ -10,7 +9,6 @@ import (
"mayfly-go/pkg/errorx" "mayfly-go/pkg/errorx"
"mayfly-go/pkg/logx" "mayfly-go/pkg/logx"
"mayfly-go/pkg/model" "mayfly-go/pkg/model"
"mayfly-go/pkg/utils/jsonx"
"strings" "strings"
) )
@@ -56,16 +54,14 @@ func (a *configAppImpl) Save(ctx context.Context, config *entity.Config) error {
func (a *configAppImpl) GetConfig(key string) *entity.Config { func (a *configAppImpl) GetConfig(key string) *entity.Config {
config := &entity.Config{Key: key} config := &entity.Config{Key: key}
// 优先从缓存中获取 // 优先从缓存中获取
cacheStr := cache.GetStr(SysConfigKeyPrefix + key) if exist := cache.Get(SysConfigKeyPrefix+key, &config); exist {
if cacheStr != "" {
json.Unmarshal([]byte(cacheStr), &config)
return config return config
} }
if err := a.GetByCond(model.NewModelCond(config).Columns("Id", "Key", "Value", "Permission")); err != nil { 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) logx.Warnf("There is no system configuration with key = [%s]", key)
} else { } else {
cache.SetStr(SysConfigKeyPrefix+key, jsonx.ToStr(config), -1) cache.Set(SysConfigKeyPrefix+key, config, -1)
} }
return config return config
} }

View File

@@ -419,14 +419,12 @@ func (p *tagTreeAppImpl) GetAccountTags(accountId uint64, query *entity.TagTreeQ
continue continue
} }
// 如用户分配了: "default/type1|code1/type2|code2/type3|code3/", 需要查询的codePathLike为: default/type1|%/type2|%/,即用户分配的标签路径是查询的子节点。 // 如用户分配了: "default/type1|code1/type2|code2/type3|code3/",即accountMathPath=default/type1|%/type2|%/type3/%/, 需要查询的codePathLike为: default/type1|%/type2|%/,即用户分配的标签路径是查询的子节点。
// 若需要获取所有子节点,则codePathLike 使用default/type1|code1/type2|code2/去查。否则需要单独再去查一遍 // 则codePathLike 使用default/type1|code1/type2|code2/去查
if strings.HasPrefix(accountMatchPath, codePathLike) { if strings.HasPrefix(accountMatchPath, codePathLike) {
actualMatchCodePath := accountTagCodePathSections[len(entity.CodePath(codePathLike).GetPathSections())-1].Path actualMatchCodePath := accountTagCodePathSections[len(entity.CodePath(codePathLike).GetPathSections())-1].Path
needFilterAccountTagPaths[actualMatchCodePath] = append(needFilterAccountTagPaths[actualMatchCodePath], accountTag) needFilterAccountTagPaths[actualMatchCodePath] = append(needFilterAccountTagPaths[actualMatchCodePath], accountTag)
if query.GetAllChildren { codePathLikes = append(codePathLikes, actualMatchCodePath)
codePathLikes = append(codePathLikes, actualMatchCodePath)
}
} }
} }
} }
@@ -444,19 +442,8 @@ func (p *tagTreeAppImpl) GetAccountTags(accountId uint64, query *entity.TagTreeQ
tagResourceQuery.CodePathLikes = codePathLikes tagResourceQuery.CodePathLikes = codePathLikes
p.ListByQuery(tagResourceQuery, &tagResources) 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 {
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 {
tagResources = collx.ArrayFilter(tagResources, func(tr *dto.SimpleTagTree) bool { tagResources = collx.ArrayFilter(tagResources, func(tr *dto.SimpleTagTree) bool {
for codePathLike, accountTags := range needFilterAccountTagPaths { for codePathLike, accountTags := range needFilterAccountTagPaths {
if strings.HasPrefix(tr.CodePath, codePathLike) { if strings.HasPrefix(tr.CodePath, codePathLike) {

View File

@@ -1,25 +1,72 @@
package cache package cache
import (
"mayfly-go/pkg/utils/anyx"
"mayfly-go/pkg/utils/jsonx"
"time"
"github.com/may-fly/cast"
)
type Cache interface { type Cache interface {
// 添加缓存,如果缓存则返回错误 // Set 设置缓存值
Add(k string, v any) error // duration == -1 则为永久缓存
Set(key string, value any, duration time.Duration) error
// 如果不存在则添加缓存值,否则直接返回 // Set2Str 将value转为字符串后设置缓存值
AddIfAbsent(k string, v any) Set2Str(key string, value any, duration time.Duration) error
// 如果存在则直接返回否则调用getValue回调函数获取值并添加该缓存值 // Get 获取缓存值
// @return 缓存值
ComputeIfAbsent(k string, getValueFunc func(string) (any, error)) (any, error)
// 获取缓存值参数1为值参数2->是否存在该缓存
Get(k string) (any, bool) 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 Count() int
// 删除缓存 // Clear 清空所有缓存
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
View 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
View 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
View 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())
}

View File

@@ -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)
}
}

View File

@@ -12,10 +12,6 @@ import (
"encoding/hex" "encoding/hex"
"encoding/pem" "encoding/pem"
"errors" "errors"
"mayfly-go/pkg/cache"
"mayfly-go/pkg/logx"
"mayfly-go/pkg/model"
"os"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@@ -106,119 +102,6 @@ func RsaDecrypt(privateKeyStr string, data []byte) ([]byte, error) {
return rsa.DecryptPKCS1v15(rand.Reader, priv, data) 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 加密 // AesEncrypt 加密
func AesEncrypt(data []byte, key []byte) ([]byte, error) { func AesEncrypt(data []byte, key []byte) ([]byte, error) {
//创建加密实例 //创建加密实例
@@ -281,12 +164,6 @@ func AesDecryptBase64(data string, key []byte) ([]byte, error) {
return AesDecrypt(dataByte, key) 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 填充 // pkcs7Padding 填充
func pkcs7Padding(data []byte, blockSize int) []byte { func pkcs7Padding(data []byte, blockSize int) []byte {
//判断缺少几位长度。最少1最多 blockSize //判断缺少几位长度。最少1最多 blockSize