mirror of
				https://github.com/bufanyun/hotgo.git
				synced 2025-11-04 16:23:43 +08:00 
			
		
		
		
	@@ -69,7 +69,7 @@
 | 
			
		||||
16. 插件应用:支持一键生成插件模板,每个插件之间开发隔离,拥有独立多应用入口、独立配置。完美支持多人协同开发、插件插拔不会对原系统产生影响等。
 | 
			
		||||
17. 服务监控:监视当前系统CPU、内存、磁盘、网络、堆栈等相关信息。
 | 
			
		||||
18. 附件管理:文件图片上传,支持本地、阿里云oss、腾讯云cos、ucloud对象存储、七牛云对象存储等多种上传驱动,后台一键切换配置。
 | 
			
		||||
19. TCP服务:基于gtcp的应用化实例,支持长连接、断线重连、自动维护心跳、服务登录、服务授权等。主要用于网络服务进程之间的消息通讯。
 | 
			
		||||
19. TCP服务:基于gtcp的应用实例,支持长连接、断线重连、自动维护心跳、签名、服务登录、服务授权等。主要用于C/S服务器和服务进程之间的数据通讯。
 | 
			
		||||
20. 消息队列:同时兼容 kafka、redis、rocketmq、磁盘队列,一键配置切换到场景适用的MQ。
 | 
			
		||||
21. 通知公告:采用websocket实时推送在线用户最新通知、公告、私信消息。
 | 
			
		||||
22. 地区编码:整合国内通用省市区编码,运用于项目于一身,支持动态省市区选项。
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,8 @@
 | 
			
		||||
- [目录结构](sys-catalog.md)
 | 
			
		||||
- [开发规范](sys-exploit.md)
 | 
			
		||||
- [控制台](sys-console.md)
 | 
			
		||||
- 请求中间件和WebHook
 | 
			
		||||
- [中间件/拦截器](sys-middleware.md)
 | 
			
		||||
- [WebHook](sys-webhook.md)
 | 
			
		||||
- [权限控制](sys-auth.md)
 | 
			
		||||
- [支付网关](sys-payment.md)
 | 
			
		||||
- [数据库](sys-db.md)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								docs/guide-zh-CN/images/sys-middleware-error-log.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/guide-zh-CN/images/sys-middleware-error-log.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 57 KiB  | 
@@ -13,6 +13,7 @@
 | 
			
		||||
- 仅推荐在开发期间快速调试使用,线上实际部署时建议将各个服务分开部署,这样重新部署某个服务时无需全部重启。
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
 | 
			
		||||
# 默认
 | 
			
		||||
go run main.go
 | 
			
		||||
 | 
			
		||||
@@ -22,6 +23,7 @@ gf run main.go
 | 
			
		||||
 | 
			
		||||
### HTTP服务
 | 
			
		||||
- 启动HTTP服务,包含websocket。
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
# 默认
 | 
			
		||||
go run main.go http
 | 
			
		||||
@@ -41,7 +43,7 @@ go run main.go queue
 | 
			
		||||
gf run main.go --args "queue"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 定时任务(暂未拆分,目前随HTTP服务启动)
 | 
			
		||||
### 定时任务
 | 
			
		||||
- 启动系统中统一注册的定时任务。
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
@@ -55,6 +57,8 @@ gf run main.go --args "cron"
 | 
			
		||||
 | 
			
		||||
### 常用工具
 | 
			
		||||
- 释放casbin权限,用于清理无效的权限设置。
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
go run main.go tools -m=casbin -a1=refresh
 | 
			
		||||
```
 | 
			
		||||
@@ -62,6 +66,7 @@ go run main.go tools -m=casbin -a1=refresh
 | 
			
		||||
 | 
			
		||||
### Makefile
 | 
			
		||||
- 通过make提供一些快捷命令
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
# 一键编译,打包前后端代码到可执行文件
 | 
			
		||||
make build
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										204
									
								
								docs/guide-zh-CN/sys-middleware.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								docs/guide-zh-CN/sys-middleware.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,204 @@
 | 
			
		||||
## 中间件/拦截器
 | 
			
		||||
 | 
			
		||||
目录
 | 
			
		||||
 | 
			
		||||
- 介绍
 | 
			
		||||
- 全局中间件
 | 
			
		||||
- 鉴权中间件
 | 
			
		||||
- 响应中间件
 | 
			
		||||
- 更多
 | 
			
		||||
 | 
			
		||||
### 介绍
 | 
			
		||||
- 在hotgo中,中间件/拦截器主要作用于web请求的上下文预设、跨域请求处理、鉴权处理、请求拦截和请求结束后统一响应处理等。
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### 全局中间件
 | 
			
		||||
```go
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"hotgo/internal/service"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main()  {
 | 
			
		||||
	
 | 
			
		||||
	// 初始化请求上下文,一般需要第一个进行加载,后续中间件存在依赖关系
 | 
			
		||||
	service.Middleware().Ctx() 
 | 
			
		||||
	
 | 
			
		||||
	// 跨域中间件,自动处理跨域问题
 | 
			
		||||
	service.Middleware().CORS()
 | 
			
		||||
	
 | 
			
		||||
	// IP黑名单中间件,如果请求IP被后台拉黑,所有请求将被拒绝
 | 
			
		||||
	service.Middleware().Blacklist()
 | 
			
		||||
	
 | 
			
		||||
	// 演示系統操作限制,当开启演示模式时,所有POST请求将被拒绝
 | 
			
		||||
	service.Middleware().DemoLimit()
 | 
			
		||||
	
 | 
			
		||||
	// HTTP响应预处理,在业务处理完成后,对响应结果进行格式化和错误过滤,将处理后的数据发送给请求方
 | 
			
		||||
	service.Middleware().ResponseHandler()
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
### 鉴权中间件
 | 
			
		||||
```go
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gogf/gf/v2/frame/g"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main()  {
 | 
			
		||||
	
 | 
			
		||||
	// 在鉴权中间件下的路由如果没有通过权限验证,后续请求将被拒绝
 | 
			
		||||
	// 在hotgo中,鉴权中间件一般是配合一个业务模块下的路由组进行使用
 | 
			
		||||
	// 目前admin、api、home、websocket模块都已接入
 | 
			
		||||
	// 如果你需要创建一个新的模块也需要用到鉴权中间件,可以参考:server/internal/logic/middleware/admin_auth.go
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	// 一个简单例子
 | 
			
		||||
	s := g.Server()
 | 
			
		||||
	s.Group("/api", func(group *ghttp.RouterGroup) {
 | 
			
		||||
		group.Middleware(service.Middleware().ApiAuth)
 | 
			
		||||
		group.Bind(
 | 
			
		||||
			member.Member, // 管理员
 | 
			
		||||
		)
 | 
			
		||||
	})
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 响应中间件
 | 
			
		||||
- 文件路径:server/internal/logic/middleware/response.go
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### 自定义响应
 | 
			
		||||
- 由于响应中间件是全局的,并且是统一使用json格式进行响应的,但是在实际的开发中可能存在一些需要使用非json格式的响应,所以你需要进行单独的处理。
 | 
			
		||||
- 推荐以下几种处理方式,可做参考:
 | 
			
		||||
1. 使用`ghttp.ExitAll()`,需要注意的是此方法会终止后续所有的http处理
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gogf/gf/v2/net/ghttp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main()  {
 | 
			
		||||
	r := new(ghttp.Request) // 当前请求对象
 | 
			
		||||
 | 
			
		||||
	// 清空响应
 | 
			
		||||
	r.Response.ClearBuffer()
 | 
			
		||||
 | 
			
		||||
	// 写入响应
 | 
			
		||||
	r.Response.Write("自定义响应内容")
 | 
			
		||||
	
 | 
			
		||||
	// 终止后续http处理
 | 
			
		||||
	r.ExitAll()
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
2. 在`server/internal/logic/middleware/response.go`中根据请求的独有特征进行单独的处理,兼容后续http处理。
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### 重写响应错误提示
 | 
			
		||||
 | 
			
		||||
- 在实际开发中,我们可能想要隐藏一些敏感错误,返回给客户端友好的错误提示,但开发者同时又想需要看到真实的敏感错误。对此hotgo已经进行了过滤处理,下面是一个简单的例子:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gogf/gf/v2/errors/gerror"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func test() error {
 | 
			
		||||
	err = gerror.New("这是一个sql执行错误")
 | 
			
		||||
	err = gerror.Wrap(err, "用户创建失败,请稍后重试!~")
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- 开启debug时的客户端响应:
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "code": -1,
 | 
			
		||||
  "message": "用户创建失败,请稍后重试!~",
 | 
			
		||||
  "error": [
 | 
			
		||||
    "1. 用户创建失败,请稍后重试!~",
 | 
			
		||||
    "   1).  hotgo/internal/logic/admin.(*sAdminMember).List",
 | 
			
		||||
    "        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:526",
 | 
			
		||||
    "2. 这是一个sql执行错误", "   1).  hotgo/internal/logic/admin.(*sAdminMember).List",
 | 
			
		||||
    "        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:525",
 | 
			
		||||
    "   2).  hotgo/internal/controller/admin/admin.(*cMember).List",
 | 
			
		||||
    "        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/controller/admin/admin/member.go:157", "   3).  github.com/gogf/gf/v2/net/ghttp.(*middleware).callHandlerFunc.func1", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:152", "   4).  github.com/gogf/gf/v2/net/ghttp.niceCallFunc", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_func.go:55", "   5).  github.com/gogf/gf/v2/net/ghttp.(*middleware).callHandlerFunc", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:129", "   6).  github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:75", "   7).  github.com/gogf/gf/v2/util/gutil.TryCatch", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/util/gutil/gutil.go:56", "   8).  github.com/gogf/gf/v2/net/ghttp.(*middleware).Next", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:49", "   9).  hotgo/internal/logic/middleware.(*sMiddleware).AdminAuth", "        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/admin_auth.go:53", "   10). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.1", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:55", "   11). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:54", "   12). hotgo/internal/logic/middleware.(*sMiddleware).ResponseHandler", "        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/response.go:24", "   13). hotgo/internal/logic/middleware.(*sMiddleware).DemoLimit", "        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/init.go:90", "   14). hotgo/internal/logic/middleware.(*sMiddleware).Blacklist", "        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/limit_blacklist.go:22", "   15). hotgo/internal/logic/middleware.(*sMiddleware).CORS", "        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/init.go:83", "   16). hotgo/internal/logic/middleware.(*sMiddleware).Ctx", "        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/init.go:62", "   17). github.com/gogf/gf/v2/net/ghttp.internalMiddlewareServerTracing", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_middleware_tracing.go:79", "   18). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.5", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:96", "   19). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_request_middleware.go:95", "   20). github.com/gogf/gf/v2/net/ghttp.(*Server).ServeHTTP", "        E:/gopath/pkg/mod/github.com/gogf/gf/v2@v2.4.1/net/ghttp/ghttp_server_handler.go:132", ""
 | 
			
		||||
  ],
 | 
			
		||||
  "timestamp": 1684145107,
 | 
			
		||||
  "traceID": "084022730d495f17f19e550140f3e1a8"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- 关闭debug时的客户端响应:
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "code": -1,
 | 
			
		||||
  "message": "用户创建失败,请稍后重试!~",
 | 
			
		||||
  "timestamp": 1684145107,
 | 
			
		||||
  "traceID": "084022730d495f17f19e550140f3e1a8"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- 控制台的输出日志:
 | 
			
		||||
```shell
 | 
			
		||||
2023-05-15 18:05:07.776 {084022730d495f17f19e550140f3e1a8} 200 "GET http localhost:8000 /admin/member/list?page=1&pageSize=10&roleId=-1 HTTP/1.1" 0.002, 127.0.0.1, "http://192.168.0.207:8001/login", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Co
 | 
			
		||||
re/1.94.197.400 QQBrowser/11.7.5287.400", -1, "", ""
 | 
			
		||||
Stack:
 | 
			
		||||
1. 用户创建失败,请稍后重试!~
 | 
			
		||||
   1).  hotgo/internal/logic/admin.(*sAdminMember).List
 | 
			
		||||
        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/admin/member.go:526
 | 
			
		||||
2. 这是一个sql执行错误
 | 
			
		||||
   1).  hotgo/internal/logic/admin.(*sAdminMember).List
 | 
			
		||||
        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/response.go:24
 | 
			
		||||
   13). hotgo/internal/logic/middleware.(*sMiddleware).DemoLimit
 | 
			
		||||
        E:/Users/Administrator/Desktop/gosrc/hotgo_dev/server/internal/logic/middleware/init.go:90
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- 如果你开启了访问日志,那么日志记录中会详细记录本次请求的相关信息,内容如下:
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### 重写错误码
 | 
			
		||||
- hotgo默认使用了gf内置的错误码进行业务处理,通常情况下成功状态码为`0`,失败状态码为`-1`
 | 
			
		||||
- 查看gf内置错误码:https://goframe.org/pages/viewpage.action?pageId=30739587
 | 
			
		||||
- 以下是自定义错误码的简单例子:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gogf/gf/v2/errors/gerror"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func test() error {
 | 
			
		||||
	// 使用自定义状态码30001响应客户端
 | 
			
		||||
	err = gerror.NewCode(gcode.New(30001, "用户创建失败,请稍后重试!~", nil))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
- 客户端响应如下:
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
	"code": 30001,
 | 
			
		||||
	"message": "用户创建失败,请稍后重试!~",
 | 
			
		||||
	"timestamp": 1684146313,
 | 
			
		||||
	"traceID": "b4f90e16264a5f17cd3fc27141aba448"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 更多
 | 
			
		||||
- 更多关于中间件/拦截器的介绍请参考:https://goframe.org/pages/viewpage.action?pageId=55289881
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								docs/guide-zh-CN/sys-webhook.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								docs/guide-zh-CN/sys-webhook.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
## WebHook
 | 
			
		||||
 | 
			
		||||
待写
 | 
			
		||||
@@ -7,9 +7,9 @@ package cmd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"github.com/gogf/gf/v2/frame/g"
 | 
			
		||||
	"github.com/gogf/gf/v2/os/gcmd"
 | 
			
		||||
	"hotgo/internal/service"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@@ -20,17 +20,17 @@ var (
 | 
			
		||||
		Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
 | 
			
		||||
			service.AuthClient().Start(ctx)
 | 
			
		||||
 | 
			
		||||
			// 退出信号监听
 | 
			
		||||
			signalListen(ctx, func(sig os.Signal) {
 | 
			
		||||
				service.AuthClient().Stop(ctx)
 | 
			
		||||
			})
 | 
			
		||||
			serverWg.Add(1)
 | 
			
		||||
 | 
			
		||||
			// 信号监听
 | 
			
		||||
			signalListen(ctx, signalHandlerForOverall)
 | 
			
		||||
			select {
 | 
			
		||||
			case <-serverCloseSignal:
 | 
			
		||||
				// ...
 | 
			
		||||
				service.AuthClient().Stop(ctx)
 | 
			
		||||
				serverWg.Done()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			g.Log().Debug(ctx, "auth successfully closed ..")
 | 
			
		||||
			return
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	serverCloseSignal chan struct{}
 | 
			
		||||
	Main              = &gcmd.Command{
 | 
			
		||||
	Main = &gcmd.Command{
 | 
			
		||||
		Description: `默认启动所有服务`,
 | 
			
		||||
		Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
 | 
			
		||||
			return All.Func(ctx, parser)
 | 
			
		||||
@@ -76,10 +75,10 @@ var (
 | 
			
		||||
 | 
			
		||||
			select {
 | 
			
		||||
			case <-serverCloseSignal:
 | 
			
		||||
				// ...
 | 
			
		||||
				serverWg.Wait()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			g.Log().Debug(ctx, "service successfully closed ..")
 | 
			
		||||
			g.Log().Debug(ctx, "all service successfully closed ..")
 | 
			
		||||
			return
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
@@ -89,5 +88,4 @@ func init() {
 | 
			
		||||
	if err := Main.AddCommand(All, Http, Queue, Cron, Auth, Tools, Help); err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	serverCloseSignal = make(chan struct{}, 1)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,10 +7,10 @@ package cmd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"github.com/gogf/gf/v2/frame/g"
 | 
			
		||||
	"github.com/gogf/gf/v2/os/gcmd"
 | 
			
		||||
	"hotgo/internal/crons"
 | 
			
		||||
	"hotgo/internal/service"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@@ -25,17 +25,18 @@ var (
 | 
			
		||||
			// tcp客户端
 | 
			
		||||
			service.CronClient().Start(ctx)
 | 
			
		||||
 | 
			
		||||
			// 退出信号监听
 | 
			
		||||
			signalListen(ctx, func(sig os.Signal) {
 | 
			
		||||
				service.CronClient().Stop(ctx)
 | 
			
		||||
				crons.StopALL()
 | 
			
		||||
				serverCloseSignal <- struct{}{}
 | 
			
		||||
			})
 | 
			
		||||
			serverWg.Add(1)
 | 
			
		||||
 | 
			
		||||
			// 信号监听
 | 
			
		||||
			signalListen(ctx, signalHandlerForOverall)
 | 
			
		||||
			select {
 | 
			
		||||
			case <-serverCloseSignal:
 | 
			
		||||
				// ...
 | 
			
		||||
				service.CronClient().Stop(ctx)
 | 
			
		||||
				crons.StopALL()
 | 
			
		||||
				serverWg.Done()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			g.Log().Debug(ctx, "cron successfully closed ..")
 | 
			
		||||
			return
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@
 | 
			
		||||
// @Copyright  Copyright (c) 2023 HotGo CLI
 | 
			
		||||
// @Author  Ms <133814250@qq.com>
 | 
			
		||||
// @License  https://github.com/bufanyun/hotgo/blob/master/LICENSE
 | 
			
		||||
//
 | 
			
		||||
package cmd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
@@ -11,6 +10,12 @@ import (
 | 
			
		||||
	"github.com/gogf/gf/v2/os/gproc"
 | 
			
		||||
	"hotgo/utility/simple"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	serverCloseSignal = make(chan struct{}, 1)
 | 
			
		||||
	serverWg          = sync.WaitGroup{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func signalHandlerForOverall(sig os.Signal) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,13 +10,11 @@ import (
 | 
			
		||||
	"github.com/gogf/gf/v2/frame/g"
 | 
			
		||||
	"github.com/gogf/gf/v2/net/ghttp"
 | 
			
		||||
	"github.com/gogf/gf/v2/os/gcmd"
 | 
			
		||||
	"hotgo/internal/crons"
 | 
			
		||||
	"hotgo/internal/library/addons"
 | 
			
		||||
	"hotgo/internal/library/casbin"
 | 
			
		||||
	"hotgo/internal/router"
 | 
			
		||||
	"hotgo/internal/service"
 | 
			
		||||
	"hotgo/internal/websocket"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@@ -77,13 +75,20 @@ var (
 | 
			
		||||
			// https
 | 
			
		||||
			setSSL(ctx, s)
 | 
			
		||||
 | 
			
		||||
			// 退出信号监听
 | 
			
		||||
			signalListen(ctx, func(sig os.Signal) {
 | 
			
		||||
				s.Shutdown()
 | 
			
		||||
				crons.StopALL()
 | 
			
		||||
				websocket.Stop()
 | 
			
		||||
				service.TCPServer().Stop(ctx)
 | 
			
		||||
			})
 | 
			
		||||
			serverWg.Add(1)
 | 
			
		||||
 | 
			
		||||
			// 信号监听
 | 
			
		||||
			signalListen(ctx, signalHandlerForOverall)
 | 
			
		||||
			go func() {
 | 
			
		||||
				select {
 | 
			
		||||
				case <-serverCloseSignal:
 | 
			
		||||
					websocket.Stop()
 | 
			
		||||
					service.TCPServer().Stop(ctx)
 | 
			
		||||
					s.Shutdown() // 主服务建议放在最后一个关闭
 | 
			
		||||
					g.Log().Debug(ctx, "http successfully closed ..")
 | 
			
		||||
					serverWg.Done()
 | 
			
		||||
				}
 | 
			
		||||
			}()
 | 
			
		||||
 | 
			
		||||
			// Just run the server.
 | 
			
		||||
			s.Run()
 | 
			
		||||
 
 | 
			
		||||
@@ -25,12 +25,14 @@ var (
 | 
			
		||||
				g.Log().Debug(ctx, "start queue consumer success..")
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			serverWg.Add(1)
 | 
			
		||||
 | 
			
		||||
			// 信号监听
 | 
			
		||||
			signalListen(ctx, signalHandlerForOverall)
 | 
			
		||||
 | 
			
		||||
			select {
 | 
			
		||||
			case <-serverCloseSignal:
 | 
			
		||||
				// ...
 | 
			
		||||
				serverWg.Done()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			g.Log().Debug(ctx, "queue successfully closed ..")
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,9 @@ package consts
 | 
			
		||||
 | 
			
		||||
import "github.com/gogf/gf/v2/util/gconv"
 | 
			
		||||
 | 
			
		||||
// RequestEncryptKey 请求加密密钥用于敏感数据加密,16位字符,前后端需保持一致。安全起见请修改此值
 | 
			
		||||
// RequestEncryptKey
 | 
			
		||||
// 请求加密密钥用于敏感数据加密,16位字符,前后端需保持一致
 | 
			
		||||
// 安全起见,生产环境运行时请注意修改
 | 
			
		||||
var RequestEncryptKey = []byte("f080a463654b2279")
 | 
			
		||||
 | 
			
		||||
// 配置数据类型
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@ func Build(ctx context.Context, sk Skeleton, conf *model.BuildAddonConfig) (err
 | 
			
		||||
			"@{.description}": sk.Description,
 | 
			
		||||
			"@{.author}":      sk.Author,
 | 
			
		||||
			"@{.version}":     sk.Version,
 | 
			
		||||
			"@{.hgVersion}":   consts.VersionApp, // HG 版本
 | 
			
		||||
		}
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -195,7 +195,9 @@ func (client *Client) connect() {
 | 
			
		||||
reconnect:
 | 
			
		||||
	conn := client.dial()
 | 
			
		||||
	if conn == nil {
 | 
			
		||||
		client.Logger.Debugf(client.Ctx, "client dial failed")
 | 
			
		||||
		if !client.stopFlag {
 | 
			
		||||
			client.Logger.Debugf(client.Ctx, "client dial failed")
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -311,6 +313,11 @@ func (client *Client) Stop() {
 | 
			
		||||
	client.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsStop 是否已停止
 | 
			
		||||
func (client *Client) IsStop() bool {
 | 
			
		||||
	return client.stopFlag
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Destroy 销毁当前连接
 | 
			
		||||
func (client *Client) Destroy() {
 | 
			
		||||
	client.stopCron()
 | 
			
		||||
 
 | 
			
		||||
@@ -294,6 +294,11 @@ func (server *Server) Close() {
 | 
			
		||||
	server.wgLn.Wait()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsClose 服务是否关闭
 | 
			
		||||
func (server *Server) IsClose() bool {
 | 
			
		||||
	return server.closeFlag
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write 向指定客户端发送消息
 | 
			
		||||
func (server *Server) Write(conn *gtcp.Conn, data interface{}) (err error) {
 | 
			
		||||
	if server.closeFlag {
 | 
			
		||||
 
 | 
			
		||||
@@ -99,6 +99,8 @@ func Logout(r *ghttp.Request) (err error) {
 | 
			
		||||
 | 
			
		||||
	claims, err := parseToken(ctx, header)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		g.Log().Debugf(ctx, "logout parseToken err:%+v", err)
 | 
			
		||||
		err = errorLogin
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -138,10 +140,13 @@ func ParseLoginUser(r *ghttp.Request) (user *model.Identity, err error) {
 | 
			
		||||
 | 
			
		||||
	claims, err := parseToken(ctx, header)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		g.Log().Debugf(ctx, "parseToken err:%+v", err)
 | 
			
		||||
		err = errorLogin
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		// 认证key
 | 
			
		||||
		authKey = GetAuthKey(header)
 | 
			
		||||
		// 登录token
 | 
			
		||||
		tokenKey = GetTokenKey(claims.App, authKey)
 | 
			
		||||
@@ -285,7 +290,7 @@ func GetAuthorization(r *ghttp.Request) string {
 | 
			
		||||
 | 
			
		||||
// GetAuthKey 认证key
 | 
			
		||||
func GetAuthKey(token string) string {
 | 
			
		||||
	return gmd5.MustEncryptString(token)
 | 
			
		||||
	return gmd5.MustEncryptString("hotgo" + token)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTokenKey 令牌缓存key
 | 
			
		||||
 
 | 
			
		||||
@@ -227,18 +227,18 @@ func (s *sAdminMember) UpdateMobile(ctx context.Context, in adminin.MemberUpdate
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var memberInfo *entity.AdminMember
 | 
			
		||||
	if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&memberInfo); err != nil {
 | 
			
		||||
	var mb *entity.AdminMember
 | 
			
		||||
	if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&mb); err != nil {
 | 
			
		||||
		err = gerror.Wrap(err, consts.ErrorORM)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if memberInfo == nil {
 | 
			
		||||
	if mb == nil {
 | 
			
		||||
		err = gerror.New("用户信息不存在")
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if memberInfo.Mobile == in.Mobile {
 | 
			
		||||
	if mb.Mobile == in.Mobile {
 | 
			
		||||
		err = gerror.New("新旧手机号不能一样")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -249,10 +249,10 @@ func (s *sAdminMember) UpdateMobile(ctx context.Context, in adminin.MemberUpdate
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 存在原绑定号码,需要进行验证
 | 
			
		||||
	if memberInfo.Mobile != "" {
 | 
			
		||||
	if mb.Mobile != "" {
 | 
			
		||||
		err = service.SysSmsLog().VerifyCode(ctx, sysin.VerifyCodeInp{
 | 
			
		||||
			Event:  consts.SmsTemplateBind,
 | 
			
		||||
			Mobile: memberInfo.Mobile,
 | 
			
		||||
			Mobile: mb.Mobile,
 | 
			
		||||
			Code:   in.Code,
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@@ -264,8 +264,7 @@ func (s *sAdminMember) UpdateMobile(ctx context.Context, in adminin.MemberUpdate
 | 
			
		||||
		dao.AdminMember.Columns().Mobile: in.Mobile,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Data(update).Update()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if _, err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Data(update).Update(); err != nil {
 | 
			
		||||
		err = gerror.Wrap(err, consts.ErrorORM)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -281,13 +280,13 @@ func (s *sAdminMember) UpdateProfile(ctx context.Context, in adminin.MemberUpdat
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var memberInfo *entity.AdminMember
 | 
			
		||||
	if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&memberInfo); err != nil {
 | 
			
		||||
	var mb *entity.AdminMember
 | 
			
		||||
	if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&mb); err != nil {
 | 
			
		||||
		err = gerror.Wrap(err, consts.ErrorORM)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if memberInfo == nil {
 | 
			
		||||
	if mb == nil {
 | 
			
		||||
		err = gerror.New("用户信息不存在")
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -302,8 +301,7 @@ func (s *sAdminMember) UpdateProfile(ctx context.Context, in adminin.MemberUpdat
 | 
			
		||||
		dao.AdminMember.Columns().Address:  in.Address,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Data(update).Update()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if _, err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Data(update).Update(); err != nil {
 | 
			
		||||
		err = gerror.Wrap(err, consts.ErrorORM)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -718,7 +716,9 @@ func (s *sAdminMember) MemberLoginStat(ctx context.Context, in adminin.MemberLog
 | 
			
		||||
 | 
			
		||||
// GetIdByCode 通过邀请码获取用户ID
 | 
			
		||||
func (s *sAdminMember) GetIdByCode(ctx context.Context, in adminin.GetIdByCodeInp) (res *adminin.GetIdByCodeModel, err error) {
 | 
			
		||||
	err = dao.AdminMember.Ctx(ctx).Fields(adminin.GetIdByCodeModel{}).Where("invite_code", in.Code).Scan(&res)
 | 
			
		||||
	if err = dao.AdminMember.Ctx(ctx).Fields(adminin.GetIdByCodeModel{}).Where("invite_code", in.Code).Scan(&res); err != nil {
 | 
			
		||||
		err = gerror.Wrap(err, consts.ErrorORM)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -728,6 +728,9 @@ func (s *sAdminMember) Select(ctx context.Context, in adminin.MemberSelectInp) (
 | 
			
		||||
		Fields("id as value,real_name as label,username,avatar").
 | 
			
		||||
		Handler(handler.FilterAuthWithField("id")).
 | 
			
		||||
		Scan(&res)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = gerror.Wrap(err, consts.ErrorORM)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@ import (
 | 
			
		||||
	"hotgo/internal/dao"
 | 
			
		||||
	"hotgo/internal/library/token"
 | 
			
		||||
	"hotgo/internal/model"
 | 
			
		||||
	"hotgo/internal/model/do"
 | 
			
		||||
	"hotgo/internal/model/entity"
 | 
			
		||||
	"hotgo/internal/model/input/adminin"
 | 
			
		||||
	"hotgo/internal/model/input/sysin"
 | 
			
		||||
@@ -255,16 +254,6 @@ func (s *sAdminSite) handleLogin(ctx context.Context, mb *entity.AdminMember) (r
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	update := do.AdminMember{
 | 
			
		||||
		LastActiveAt: user.LoginAt,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 更新登录信息
 | 
			
		||||
	if _, err = dao.AdminMember.Ctx(ctx).Data(update).Where(do.AdminMember{Id: mb.Id}).Update(); err != nil {
 | 
			
		||||
		err = gerror.Wrap(err, consts.ErrorORM)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res = &adminin.LoginModel{
 | 
			
		||||
		Username: user.Username,
 | 
			
		||||
		Id:       user.Id,
 | 
			
		||||
 
 | 
			
		||||
@@ -20,9 +20,9 @@ func (s *sHook) accessLog(r *ghttp.Request) {
 | 
			
		||||
	if r.IsFileRequest() {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var ctx = contexts.Detach(r.Context())
 | 
			
		||||
	modelCtx := contexts.Get(ctx)
 | 
			
		||||
	if modelCtx == nil {
 | 
			
		||||
	if contexts.Get(ctx) == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,6 @@ func (s *sHook) lastAdminActive(r *ghttp.Request) {
 | 
			
		||||
			_, err := g.Model("admin_member").
 | 
			
		||||
				Ctx(ctx).
 | 
			
		||||
				Where("id", member.Id).
 | 
			
		||||
				WhereLT("last_active_at", gtime.Now()).
 | 
			
		||||
				Data(g.Map{"last_active_at": gtime.Now()}).
 | 
			
		||||
				Update()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -101,16 +101,16 @@ func responseJson(r *ghttp.Request) {
 | 
			
		||||
 | 
			
		||||
	if err = r.GetError(); err != nil {
 | 
			
		||||
		// 记录到自定义错误日志文件
 | 
			
		||||
		g.Log().Warningf(ctx, "exception:%v", err)
 | 
			
		||||
		g.Log().Stdout(false).Printf(ctx, "exception:%v", err)
 | 
			
		||||
 | 
			
		||||
		code = gerror.Code(err).Code()
 | 
			
		||||
 | 
			
		||||
		// 是否输出错误到页面
 | 
			
		||||
		if g.Cfg().MustGet(ctx, "hotgo.debug", true).Bool() {
 | 
			
		||||
			message = err.Error()
 | 
			
		||||
			message = gerror.Current(err).Error()
 | 
			
		||||
			data = charset.ParseErrStack(err)
 | 
			
		||||
		} else {
 | 
			
		||||
			message = consts.ErrorMessage(err)
 | 
			
		||||
			message = consts.ErrorMessage(gerror.Current(err))
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		data = r.GetHandlerResponse()
 | 
			
		||||
 
 | 
			
		||||
@@ -105,7 +105,7 @@ func (s *sSysLog) AutoLog(ctx context.Context) error {
 | 
			
		||||
		var err error
 | 
			
		||||
		defer func() {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				panic(err)
 | 
			
		||||
				g.Log().Error(ctx, "autoLog err:%+v", err)
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -75,7 +75,7 @@ func (s *sAuthClient) Start(ctx context.Context) {
 | 
			
		||||
 | 
			
		||||
// Stop 停止服务
 | 
			
		||||
func (s *sAuthClient) Stop(ctx context.Context) {
 | 
			
		||||
	if s.client != nil {
 | 
			
		||||
	if s.client != nil && !s.client.IsStop() {
 | 
			
		||||
		s.client.Stop()
 | 
			
		||||
		g.Log().Debug(ctx, "AuthClient stop..")
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,7 @@ func (s *sCronClient) Start(ctx context.Context) {
 | 
			
		||||
 | 
			
		||||
// Stop 停止服务
 | 
			
		||||
func (s *sCronClient) Stop(ctx context.Context) {
 | 
			
		||||
	if s.client != nil {
 | 
			
		||||
	if s.client != nil && !s.client.IsStop() {
 | 
			
		||||
		s.client.Stop()
 | 
			
		||||
		g.Log().Debug(ctx, "CronClient stop..")
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -53,15 +53,17 @@ func (s *sTCPServer) Start(ctx context.Context) {
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		// 服务监听
 | 
			
		||||
		if err := s.serv.Listen(); err != nil {
 | 
			
		||||
			g.Log().Warningf(ctx, "TCPServer Listen err:%v", err)
 | 
			
		||||
		if err = s.serv.Listen(); err != nil {
 | 
			
		||||
			if !s.serv.IsClose() {
 | 
			
		||||
				g.Log().Warningf(ctx, "TCPServer Listen err:%v", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Stop 关闭服务
 | 
			
		||||
func (s *sTCPServer) Stop(ctx context.Context) {
 | 
			
		||||
	if s.serv != nil {
 | 
			
		||||
	if s.serv != nil && !s.serv.IsClose() {
 | 
			
		||||
		s.serv.Close()
 | 
			
		||||
		g.Log().Debug(ctx, "TCPServer stop..")
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,9 @@ package adminin
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"github.com/gogf/gf/v2/encoding/gbase64"
 | 
			
		||||
	"github.com/gogf/gf/v2/frame/g"
 | 
			
		||||
	"github.com/gogf/gf/v2/os/gtime"
 | 
			
		||||
	"hotgo/internal/consts"
 | 
			
		||||
	"hotgo/utility/encrypt"
 | 
			
		||||
	"hotgo/utility/simple"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RegisterInp 账号注册
 | 
			
		||||
@@ -20,18 +18,11 @@ type RegisterInp struct {
 | 
			
		||||
 | 
			
		||||
func (in *RegisterInp) Filter(ctx context.Context) (err error) {
 | 
			
		||||
	// 解密密码
 | 
			
		||||
	str, err := gbase64.Decode([]byte(in.Password))
 | 
			
		||||
	password, err := simple.DecryptText(in.Password)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	str, err = encrypt.AesECBDecrypt(str, consts.RequestEncryptKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	password := string(str)
 | 
			
		||||
 | 
			
		||||
	if err = g.Validator().Data(password).Rules("password").Messages("密码长度在6~18之间").Run(ctx); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
 | 
			
		||||
### 迁移或安装
 | 
			
		||||
 | 
			
		||||
1、安装 HotGo (2.1.4及以上)
 | 
			
		||||
1、安装 HotGo (@{.hgVersion}及以上)
 | 
			
		||||
 | 
			
		||||
项目介绍:https://github.com/bufanyun/hotgo
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,20 +18,30 @@ import (
 | 
			
		||||
	"hotgo/utility/encrypt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DecryptText 解密文本
 | 
			
		||||
func DecryptText(text string) (string, error) {
 | 
			
		||||
	str, err := gbase64.Decode([]byte(text))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	str, err = encrypt.AesECBDecrypt(str, consts.RequestEncryptKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return string(str), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CheckPassword 检查密码
 | 
			
		||||
func CheckPassword(input, salt, hash string) (err error) {
 | 
			
		||||
	// 解密密码
 | 
			
		||||
	password, err := gbase64.Decode([]byte(input))
 | 
			
		||||
	password, err := DecryptText(input)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	password, err = encrypt.AesECBDecrypt(password, consts.RequestEncryptKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if hash != gmd5.MustEncryptString(string(password)+salt) {
 | 
			
		||||
	if hash != gmd5.MustEncryptString(password+salt) {
 | 
			
		||||
		err = gerror.New("用户密码不正确")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <QuillEditor
 | 
			
		||||
    ref="quillEditor"
 | 
			
		||||
    ref="quillEditorRef"
 | 
			
		||||
    toolbar="full"
 | 
			
		||||
    v-model:content="content"
 | 
			
		||||
    @ready="readyQuill"
 | 
			
		||||
@@ -33,7 +33,7 @@
 | 
			
		||||
  const emit = defineEmits(['update:value']);
 | 
			
		||||
  const message = useMessage();
 | 
			
		||||
  const initFinish = ref(false);
 | 
			
		||||
  const quillEditor = ref();
 | 
			
		||||
  const quillEditorRef = ref();
 | 
			
		||||
  const content = ref();
 | 
			
		||||
  const props = withDefaults(defineProps<Props>(), {
 | 
			
		||||
    value: '',
 | 
			
		||||
@@ -41,14 +41,14 @@
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  function readyQuill() {
 | 
			
		||||
    quillEditor.value.setHTML(props.value);
 | 
			
		||||
    quillEditorRef.value.setHTML(props.value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  watch(
 | 
			
		||||
    () => props.value,
 | 
			
		||||
    (newValue) => {
 | 
			
		||||
      if (!initFinish.value) {
 | 
			
		||||
        quillEditor.value?.setHTML(newValue);
 | 
			
		||||
        quillEditorRef.value?.setHTML(newValue);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
@@ -67,7 +67,7 @@
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function onUpdateContent() {
 | 
			
		||||
    emit('update:value', quillEditor.value.getHTML());
 | 
			
		||||
    emit('update:value', quillEditorRef.value.getHTML());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function checkFileType(map: string[], fileType: string) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user