From ae07370214f7fd98f6a31da9af33453a460457bc Mon Sep 17 00:00:00 2001 From: eson <9673575+githubcontent@user.noreply.gitee.com> Date: Fri, 11 Aug 2023 17:39:18 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E7=BD=AE=E5=AF=86=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- goctl_template/api/context.tpl | 2 +- server/auth/internal/handler/routes.go | 12 +++- .../handler/userresetpasswordhandler.go | 35 ++++++++++ .../internal/handler/userresettokenhandler.go | 35 ++++++++++ .../logic/useremailconfirmationlogic.go | 2 +- .../internal/logic/useremailregisterlogic.go | 6 +- .../internal/logic/usergoogleloginlogic.go | 2 +- .../internal/logic/userresetpasswordlogic.go | 43 ++++++++++++ .../internal/logic/userresettokenlogic.go | 65 +++++++++++++++++++ server/auth/internal/svc/servicecontext.go | 14 ++-- server/auth/internal/types/types.go | 21 ++++-- server_api/assistant.api | 20 ------ server_api/auth.api | 49 ++++++++++---- utils/auth/confirmation_link.go | 3 +- utils/auth/register.go | 13 +++- utils/encryption_decryption/aes_obj_test.go | 8 +-- 16 files changed, 275 insertions(+), 55 deletions(-) create mode 100644 server/auth/internal/handler/userresetpasswordhandler.go create mode 100644 server/auth/internal/handler/userresettokenhandler.go create mode 100644 server/auth/internal/logic/userresetpasswordlogic.go create mode 100644 server/auth/internal/logic/userresettokenlogic.go delete mode 100644 server_api/assistant.api diff --git a/goctl_template/api/context.tpl b/goctl_template/api/context.tpl index f90ebc50..36b636ae 100644 --- a/goctl_template/api/context.tpl +++ b/goctl_template/api/context.tpl @@ -30,7 +30,7 @@ func NewServiceContext(c {{.config}}) *ServiceContext { return &ServiceContext{ Config: c, MysqlConn: conn, - SharedState: nil, + SharedState: nil, AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)), RabbitMq:initalize.InitRabbitMq(c.SourceRabbitMq, nil), {{.middlewareAssignment}} diff --git a/server/auth/internal/handler/routes.go b/server/auth/internal/handler/routes.go index 2206deba..b5e506b2 100644 --- a/server/auth/internal/handler/routes.go +++ b/server/auth/internal/handler/routes.go @@ -33,10 +33,20 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Handler: UserEmailConfirmationHandler(serverCtx), }, { - Method: http.MethodGet, + Method: http.MethodPost, Path: "/api/auth/oauth2/register", Handler: UserEmailRegisterHandler(serverCtx), }, + { + Method: http.MethodGet, + Path: "/api/auth/reset/token", + Handler: UserResetTokenHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/api/auth/reset/password", + Handler: UserResetPasswordHandler(serverCtx), + }, }, ) } diff --git a/server/auth/internal/handler/userresetpasswordhandler.go b/server/auth/internal/handler/userresetpasswordhandler.go new file mode 100644 index 00000000..cd072197 --- /dev/null +++ b/server/auth/internal/handler/userresetpasswordhandler.go @@ -0,0 +1,35 @@ +package handler + +import ( + "net/http" + "reflect" + + "fusenapi/utils/basic" + + "fusenapi/server/auth/internal/logic" + "fusenapi/server/auth/internal/svc" + "fusenapi/server/auth/internal/types" +) + +func UserResetPasswordHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var req types.RequestUserLogin + userinfo, err := basic.RequestParse(w, r, svcCtx, &req) + if err != nil { + return + } + + // 创建一个业务逻辑层实例 + l := logic.NewUserResetPasswordLogic(r.Context(), svcCtx) + + rl := reflect.ValueOf(l) + basic.BeforeLogic(w, r, rl) + + resp := l.UserResetPassword(&req, userinfo) + + if !basic.AfterLogic(w, r, rl, resp) { + basic.NormalAfterLogic(w, r, resp) + } + } +} diff --git a/server/auth/internal/handler/userresettokenhandler.go b/server/auth/internal/handler/userresettokenhandler.go new file mode 100644 index 00000000..6dd7fb86 --- /dev/null +++ b/server/auth/internal/handler/userresettokenhandler.go @@ -0,0 +1,35 @@ +package handler + +import ( + "net/http" + "reflect" + + "fusenapi/utils/basic" + + "fusenapi/server/auth/internal/logic" + "fusenapi/server/auth/internal/svc" + "fusenapi/server/auth/internal/types" +) + +func UserResetTokenHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var req types.Request + userinfo, err := basic.RequestParse(w, r, svcCtx, &req) + if err != nil { + return + } + + // 创建一个业务逻辑层实例 + l := logic.NewUserResetTokenLogic(r.Context(), svcCtx) + + rl := reflect.ValueOf(l) + basic.BeforeLogic(w, r, rl) + + resp := l.UserResetToken(&req, userinfo) + + if !basic.AfterLogic(w, r, rl, resp) { + basic.NormalAfterLogic(w, r, resp) + } + } +} diff --git a/server/auth/internal/logic/useremailconfirmationlogic.go b/server/auth/internal/logic/useremailconfirmationlogic.go index 4f68c009..62b7feb0 100644 --- a/server/auth/internal/logic/useremailconfirmationlogic.go +++ b/server/auth/internal/logic/useremailconfirmationlogic.go @@ -36,7 +36,7 @@ func (l *UserEmailConfirmationLogic) UserEmailConfirmation(req *types.RequestEma // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // userinfo 传入值时, 一定不为null - token, err := l.svcCtx.TokenManger.Decrypt(req.Token) + token, err := l.svcCtx.RegisterTokenManger.Decrypt(req.Token) if err != nil { logx.Error(err) return resp.SetStatus(basic.CodeOAuthRegisterTokenErr) diff --git a/server/auth/internal/logic/useremailregisterlogic.go b/server/auth/internal/logic/useremailregisterlogic.go index c665e694..38b1d37f 100644 --- a/server/auth/internal/logic/useremailregisterlogic.go +++ b/server/auth/internal/logic/useremailregisterlogic.go @@ -47,7 +47,7 @@ func (l *UserEmailRegisterLogic) UserEmailRegister(req *types.RequestEmailRegist return resp.SetStatus(basic.CodeOAuthEmailErr) } - token, err := l.svcCtx.TokenManger.Decrypt(req.RegisterToken) + token, err := l.svcCtx.RegisterTokenManger.Decrypt(req.RegisterToken) if err != nil { logx.Error(err) return resp.SetStatus(basic.CodeOAuthRegisterTokenErr) @@ -59,10 +59,10 @@ func (l *UserEmailRegisterLogic) UserEmailRegister(req *types.RequestEmailRegist // 确认email 重新序列化 token.Email = req.Email - token.WId = req.Wid + token.Wid = req.Wid token.GuestId = req.GuestId - clurl, err := l.svcCtx.TokenManger.Generate(token) + clurl, err := l.svcCtx.RegisterTokenManger.Generate(token) if err != nil { logx.Error(err) return resp.SetStatus(basic.CodeOAuthRegisterTokenErr) diff --git a/server/auth/internal/logic/usergoogleloginlogic.go b/server/auth/internal/logic/usergoogleloginlogic.go index 6883c187..7aa2a00c 100644 --- a/server/auth/internal/logic/usergoogleloginlogic.go +++ b/server/auth/internal/logic/usergoogleloginlogic.go @@ -114,7 +114,7 @@ func (l *UserGoogleLoginLogic) UserGoogleLogin(req *types.RequestGoogleLogin, us } l.isRegistered = false - token, err := l.svcCtx.TokenManger.Encrypt(l.registerInfo) + token, err := l.svcCtx.RegisterTokenManger.Encrypt(l.registerInfo) if err != nil { logx.Error(err) return resp.SetStatus(basic.CodeOAuthRegisterTokenErr) diff --git a/server/auth/internal/logic/userresetpasswordlogic.go b/server/auth/internal/logic/userresetpasswordlogic.go new file mode 100644 index 00000000..a1074861 --- /dev/null +++ b/server/auth/internal/logic/userresetpasswordlogic.go @@ -0,0 +1,43 @@ +package logic + +import ( + "fusenapi/utils/auth" + "fusenapi/utils/basic" + + "context" + + "fusenapi/server/auth/internal/svc" + "fusenapi/server/auth/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type UserResetPasswordLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewUserResetPasswordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserResetPasswordLogic { + return &UserResetPasswordLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +// 处理进入前逻辑w,r +// func (l *UserResetPasswordLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) { +// } + +func (l *UserResetPasswordLogic) UserResetPassword(req *types.RequestUserLogin, userinfo *auth.UserInfo) (resp *basic.Response) { + // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) + // userinfo 传入值时, 一定不为null + + return resp.SetStatus(basic.CodeOK) +} + +// 处理逻辑后 w,r 如:重定向, resp 必须重新处理 +// func (l *UserResetPasswordLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) { +// // httpx.OkJsonCtx(r.Context(), w, resp) +// } diff --git a/server/auth/internal/logic/userresettokenlogic.go b/server/auth/internal/logic/userresettokenlogic.go new file mode 100644 index 00000000..cdb04b18 --- /dev/null +++ b/server/auth/internal/logic/userresettokenlogic.go @@ -0,0 +1,65 @@ +package logic + +import ( + "fusenapi/utils/auth" + "fusenapi/utils/basic" + "time" + + "context" + + "fusenapi/server/auth/internal/svc" + "fusenapi/server/auth/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type UserResetTokenLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewUserResetTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserResetTokenLogic { + return &UserResetTokenLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +// 处理进入前逻辑w,r +// func (l *UserResetTokenLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) { +// } + +func (l *UserResetTokenLogic) UserResetToken(req *types.RequestUserResetToken, userinfo *auth.UserInfo) (resp *basic.Response) { + // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) + // userinfo 传入值时, 一定不为null + if !userinfo.IsUser() { + return resp.SetStatus(basic.CodeUnAuth) + } + + user, err := l.svcCtx.AllModels.FsUser.FindUserById(context.TODO(), userinfo.UserId) + if err != nil { + logx.Error(err) + return resp.SetStatus(basic.CodeRequestParamsErr, err.Error()) + } + + token := &auth.ResetToken{ + // 操作的类型, 验证的token 必须要继承这个 + OperateType: auth.OpTypeResetToken, + UserId: uint64(userinfo.UserId), + Wid: req.Wid, + Email: *user.Email, + Password: *user.PasswordHash, + CreateAt: time.Now(), + } + + l.svcCtx.ResetTokenManger.Encrypt(token) + + return resp.SetStatus(basic.CodeOK) +} + +// 处理逻辑后 w,r 如:重定向, resp 必须重新处理 +// func (l *UserResetTokenLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) { +// // httpx.OkJsonCtx(r.Context(), w, resp) +// } diff --git a/server/auth/internal/svc/servicecontext.go b/server/auth/internal/svc/servicecontext.go index 837371be..7c6227c8 100644 --- a/server/auth/internal/svc/servicecontext.go +++ b/server/auth/internal/svc/servicecontext.go @@ -22,7 +22,8 @@ type ServiceContext struct { MysqlConn *gorm.DB AllModels *gmodel.AllModelsGen - TokenManger *auth.ConfirmationLink[auth.RegisterToken] + RegisterTokenManger *auth.ConfirmationLink[auth.RegisterToken] + ResetTokenManger *auth.ConfirmationLink[auth.ResetToken] } func NewServiceContext(c config.Config) *ServiceContext { @@ -30,11 +31,12 @@ func NewServiceContext(c config.Config) *ServiceContext { // StateServer := shared.StartNode(c.ReplicaId, autoconfig.AutoGetAllServerConfig(), conn) return &ServiceContext{ - Config: c, - MysqlConn: conn, - SharedState: nil, - AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)), - TokenManger: auth.NewConfirmationLink[auth.RegisterToken](c.Auth.AccessSecret, "http://localhost:9900/api/auth/oauth2/register"), + Config: c, + MysqlConn: conn, + SharedState: nil, + AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)), + RegisterTokenManger: auth.NewConfirmationLink[auth.RegisterToken](c.Auth.AccessSecret, "http://localhost:9900/api/auth/oauth2/register"), + ResetTokenManger: auth.NewConfirmationLink[auth.ResetToken](c.Auth.AccessSecret, "http://localhost:9900/api/auth/oauth2/register"), } } diff --git a/server/auth/internal/types/types.go b/server/auth/internal/types/types.go index bdafc513..028d5866 100644 --- a/server/auth/internal/types/types.go +++ b/server/auth/internal/types/types.go @@ -10,6 +10,23 @@ type RequestUserLogin struct { Password string `json:"password"` } +type DataUserLogin struct { + Token string `json:"token"` // 登录jwt token +} + +type RequestUserResetToken struct { + Wid string `json:"wid"` +} + +type DataResetToken struct { + ResetToken string `json:"reset_token"` // 获取重置的token +} + +type RequestUserResetPassword struct { + ResetToken string `json:"reset_token"` // 附带重置token, 确保流程唯一 + Password string `json:"password"` // 附带的hash密码 +} + type RequestGoogleLogin struct { Code string `form:"code"` Scope string `form:"scope"` @@ -28,10 +45,6 @@ type RequestEmailRegister struct { RegisterToken string `json:"register_token"` } -type DataUserLogin struct { - Token string `json:"token"` // 登录jwt token -} - type DataGuest struct { Token string `json:"token"` // 登录jwt token } diff --git a/server_api/assistant.api b/server_api/assistant.api deleted file mode 100644 index 7dafa1b5..00000000 --- a/server_api/assistant.api +++ /dev/null @@ -1,20 +0,0 @@ -syntax = "v1" - -info ( - title: // TODO: add title - desc: // TODO: add description - author: "" - email: "" -) - -import "basic.api" - -service assistant { - // 处理重定向 - @handler RedirectHandler - post /api/assistant/redirect(RequestRedirect) returns (response); -} - -type RequestRedirect { - Url string `json:"url"` -} \ No newline at end of file diff --git a/server_api/auth.api b/server_api/auth.api index 410c686a..e3fddf51 100644 --- a/server_api/auth.api +++ b/server_api/auth.api @@ -23,14 +23,46 @@ service auth { get /api/auth/email/confirmation(RequestEmailConfirmation) returns (response); @handler UserEmailRegisterHandler - get /api/auth/oauth2/register(RequestEmailRegister) returns (response); + post /api/auth/oauth2/register(RequestEmailRegister) returns (response); + + @handler UserResetTokenHandler + get /api/auth/reset/token(RequestUserResetToken) returns (response); + + @handler UserResetPasswordHandler + post /api/auth/reset/password(RequestUserLogin) returns (response); } -// UserAddAddressHandler 用户登录请求结构 -type RequestUserLogin { - Email string `json:"email"` - Password string `json:"password"` -} +type ( + // UserAddAddressHandler 用户登录请求结构 + RequestUserLogin { + Email string `json:"email"` + Password string `json:"password"` + } + + // UserLoginHandler 用户登录请求结构 + DataUserLogin { + Token string `json:"token"` // 登录jwt token + } +) + +type ( + + // RequestUserResetToken 请求重置token, 一定不为null + RequestUserResetToken { + Wid string `json:"wid"` + } + + // UserResetTokenHandler 返回重置token + DataResetToken { + ResetToken string `json:"reset_token"` // 获取重置的token + } + + // RequestUserResetPassword 重置密码 + RequestUserResetPassword { + ResetToken string `json:"reset_token"` // 附带重置token, 确保流程唯一 + Password string `json:"password"` // 附带的hash密码 + } +) type RequestGoogleLogin { Code string `form:"code"` @@ -50,11 +82,6 @@ type RequestEmailRegister { RegisterToken string `json:"register_token"` } -// UserLoginHandler 用户登录请求结构 -type DataUserLogin { - Token string `json:"token"` // 登录jwt token -} - // DataGuest 游客获取toekn请求结构 type DataGuest { Token string `json:"token"` // 登录jwt token diff --git a/utils/auth/confirmation_link.go b/utils/auth/confirmation_link.go index c3392dcf..6b0115d8 100644 --- a/utils/auth/confirmation_link.go +++ b/utils/auth/confirmation_link.go @@ -8,7 +8,8 @@ import ( type OperateType int8 const ( - OpTypeRegister OperateType = 1 //注册的操作类型 + OpTypeRegister OperateType = 1 //注册的操作类型 + OpTypeResetToken OperateType = 2 //重置密码类型 ) type ConfirmationLink[T any] struct { diff --git a/utils/auth/register.go b/utils/auth/register.go index 5cff3ac6..bfd59fa7 100644 --- a/utils/auth/register.go +++ b/utils/auth/register.go @@ -14,15 +14,24 @@ import ( type RegisterToken struct { OperateType // 操作的类型, 验证的token 必须要继承这个 - Id int64 // 注册的 id + Id int64 // 注册的 id google_id 或 facebook_id ... GuestId uint64 // guest_id 需要继承 - WId string // websocket 通道id + Wid string // websocket 通道id Email string // email Password string // 密码 Platform string // 平台 CreateAt time.Time // 创建时间 } +type ResetToken struct { + OperateType // 操作的类型, 验证的token 必须要继承这个 + UserId uint64 // guest_id 需要继承 + Wid string // websocket 通道id + Email string // email + Password string // 密码 + CreateAt time.Time // 创建时间 +} + func ParseJwtTokenUint64SecretByRequest(r *http.Request, AccessSecret uint64) (jwt.MapClaims, error) { AuthKey := r.Header.Get("Authorization") if AuthKey == "" { diff --git a/utils/encryption_decryption/aes_obj_test.go b/utils/encryption_decryption/aes_obj_test.go index 9f3c9ea5..a6296d45 100644 --- a/utils/encryption_decryption/aes_obj_test.go +++ b/utils/encryption_decryption/aes_obj_test.go @@ -11,7 +11,7 @@ func TestGCM(t *testing.T) { token := &auth.RegisterToken{ OperateType: auth.OpTypeRegister, Password: "fusen_password", - WId: 123, + Wid: "123", } key := "fusen123321" @@ -31,7 +31,7 @@ func BenchmarkCRT(b *testing.B) { token := &auth.RegisterToken{ OperateType: auth.OpTypeRegister, Password: "fusen_password", - WId: 123, + Wid: "123", } key := "fusen123321" @@ -52,7 +52,7 @@ func BenchmarkGCM(b *testing.B) { token := &auth.RegisterToken{ OperateType: auth.OpTypeRegister, Password: "fusen_password", - WId: 123, + Wid: "123", } key := "fusen123321" @@ -72,7 +72,7 @@ func TestCRT(t *testing.T) { token := &auth.RegisterToken{ OperateType: auth.OpTypeRegister, Password: "fusen_password", - WId: 123, + Wid: "123", } key := "fusen123321"