From 818d1f0019f493590f2b54cc7dc0cade68c19c34 Mon Sep 17 00:00:00 2001 From: Havoc412 <2993167370@qq.com> Date: Thu, 17 Oct 2024 14:49:50 +0800 Subject: [PATCH] add user errcode --- app/global/errcode/code.go | 1 + app/global/errcode/msg.go | 1 + app/global/errcode/users.go | 9 ++++++ app/http/controller/web/users_controller.go | 28 +++++++++---------- app/http/validator/web/users/weixin_login.go | 8 +++--- app/model/users.go | 4 +-- app/service/weixin/code2Session.go | 29 ++++++++++++++++---- config/config.yml | 4 +-- routers/web.go | 3 ++ 9 files changed, 59 insertions(+), 28 deletions(-) create mode 100644 app/global/errcode/users.go diff --git a/app/global/errcode/code.go b/app/global/errcode/code.go index fba22b6..acdf82e 100644 --- a/app/global/errcode/code.go +++ b/app/global/errcode/code.go @@ -3,6 +3,7 @@ package errcode const ( ErrGeneral = (iota + 1) * 100000 ErrAnimal + ErrUser ) const ( diff --git a/app/global/errcode/msg.go b/app/global/errcode/msg.go index 24a83cd..9be6b43 100644 --- a/app/global/errcode/msg.go +++ b/app/global/errcode/msg.go @@ -8,6 +8,7 @@ func init() { ErrMsg = make(msg) GeneralMsgInit(ErrMsg) AnimalMsgInit(ErrMsg) + UserMsgInit(ErrMsg) } func GeneralMsgInit(m msg) { diff --git a/app/global/errcode/users.go b/app/global/errcode/users.go new file mode 100644 index 0000000..dd50933 --- /dev/null +++ b/app/global/errcode/users.go @@ -0,0 +1,9 @@ +package errcode + +const ( + ErrWeixinApi = iota + ErrUser +) + +func UserMsgInit(m msg) { + m[ErrWeixinApi] = "微信接口调用失败" +} diff --git a/app/http/controller/web/users_controller.go b/app/http/controller/web/users_controller.go index 6a90394..bae05f7 100644 --- a/app/http/controller/web/users_controller.go +++ b/app/http/controller/web/users_controller.go @@ -8,11 +8,9 @@ import ( userstoken "catface/app/service/users/token" "catface/app/service/weixin" "catface/app/utils/response" - "fmt" "time" "github.com/gin-gonic/gin" - ) type Users struct { @@ -38,7 +36,7 @@ func (u *Users) Login(context *gin.Context) { userName := context.GetString(consts.ValidatorPrefix + "user_name") pass := context.GetString(consts.ValidatorPrefix + "pass") phone := context.GetString(consts.ValidatorPrefix + "phone") - + // 1. 先检查 账号密码是否正确,然后再检查 Token 状态。 userModelFact := model.CreateUserFactory("") userModel := userModelFact.Login(userName, pass) @@ -157,28 +155,30 @@ func (u *Users) WeixinLogin(context *gin.Context) { userIp := context.ClientIP() // INFO 通过上下文获取 IP 信息。 // 1. 访问 微信 API 获取 openid - openId, err := weixin.Code2Session(code) + weixinRes, err := weixin.Code2Session(code) if err != nil { // 解析微信登录成功,返回用户信息 - fmt.Println(err) // TODO 换成 LOG - response.Fail(context, consts.CurdLoginFailCode, consts.CurdLoginFailMsg, "") + response.Fail(context, consts.CurdLoginFailCode, consts.CurdLoginFailMsg, err) + return } // 2. 执行 CURD - if UsersModel, err := curd.CreateUserFactory().WeixinLogin(openId, userName, userAvatar) { - if userId > 0 { + user, err := model.CreateUserFactory("mysql").WeixinLogin(weixinRes.OpenId, weixinRes.SessionKey, userName, userAvatar, userIp) + if err == nil && user != nil { + if user.Id > 0 { // 3. 生成 token - token, err := userstoken.CreateUserFactory().GenerateToken(userId, userName, "", 0) + token, err := userstoken.CreateUserFactory().GenerateToken(user.Id, userName, "", 0) if err != nil { - response.Fail(context, consts.CurdLoginFailCode, consts.CurdLoginFailMsg, "") + response.Fail(context, consts.CurdLoginFailCode, consts.CurdLoginFailMsg, err) + return } - // 4. 返回 token res := gin.H{ - "userId": UsersModel.userId, - "permission": UsersModel.Permission - "token": token, + "userId": user.Id, + "permission": user.Permission, + "token": token, } + response.Success(context, consts.CurdStatusOkMsg, res) } } else { response.Fail(context, consts.CurdLoginFailCode, consts.CurdLoginFailMsg, "") diff --git a/app/http/validator/web/users/weixin_login.go b/app/http/validator/web/users/weixin_login.go index 6d8990f..9211551 100644 --- a/app/http/validator/web/users/weixin_login.go +++ b/app/http/validator/web/users/weixin_login.go @@ -10,9 +10,9 @@ import ( ) type WeixinLogin struct { - Code string `json:"code"` - UserName string `json:"user_name"` - UserAvatar string `json:"user_avatar"` // INFO 本地缓存,不确定 url 的类型。 + Code string `form:"code" json:"code"` + UserName string `form:"user_name" json:"user_name"` + UserAvatar string `form:"user_avatar" json:"user_avatar"` // INFO 本地缓存,不确定 url 的类型。 } func (w WeixinLogin) CheckParams(context *gin.Context) { @@ -25,7 +25,7 @@ func (w WeixinLogin) CheckParams(context *gin.Context) { // INFO 该函数主要是将本结构体的字段(成员)按照 consts.ValidatorPrefix+ json标签对应的 键 => 值 形式绑定在上下文,便于下一步(控制器)可以直接通过 context.Get(键) 获取相关值 extraAddBindDataContext := data_transfer.DataAddContext(w, consts.ValidatorPrefix, context) if extraAddBindDataContext == nil { - response.ErrorSystem(context, "userLogin表单验证器json化失败", "") + response.ErrorSystem(context, "userWeixinLogin表单验证器json化失败", "") } else { // 验证完成,调用控制器,并将验证器成员(字段)递给控制器,保持上下文数据一致性 (&web.Users{}).WeixinLogin(extraAddBindDataContext) diff --git a/app/model/users.go b/app/model/users.go index f4ffb04..a192723 100644 --- a/app/model/users.go +++ b/app/model/users.go @@ -313,14 +313,14 @@ func (u *UsersModel) DelTokenCacheFromRedis(userId int64) { * @description * @return {*} */ -func (u *UsersModel) WeixinLogin(openId string, name string, avatar string) (temp *UsersModel, err error) { +func (u *UsersModel) WeixinLogin(openId, sessionKey, name, avatar, ip string) (temp *UsersModel, err error) { db := u.DB var user UsersModel if result := db.Where("open_id = ?", openId).First(&user); result.Error != nil { temp = &user } else if result.Error == gorm.ErrRecordNotFound { - newUser := UsersModel{OpenId: openId, UserName: name, UserAvatar: avatar} + newUser := UsersModel{OpenId: openId, UserName: name, UserAvatar: avatar, LastLoginIp: ip, SessionKey: sessionKey} if err := db.Create(&newUser).Error; err != nil { return nil, err } diff --git a/app/service/weixin/code2Session.go b/app/service/weixin/code2Session.go index 1d6649d..071265d 100644 --- a/app/service/weixin/code2Session.go +++ b/app/service/weixin/code2Session.go @@ -2,12 +2,20 @@ package weixin import ( "catface/app/global/variable" + "encoding/json" "fmt" "io" "net/http" ) -func Code2Session(js_code string) (string, error) { +type Response struct { + OpenId string `json:"openid"` + SessionKey string `json:"session_key"` + Errcode int `json:"errcode"` + Errmsg string `json:"errmsg"` +} + +func Code2Session(js_code string) (*Response, error) { appid := variable.ConfigYml.GetString("Weixin.AppId") appSecret := variable.ConfigYml.GetString("Weixin.AppSecret") grantType := variable.ConfigYml.GetString("Weixin.Code2Session.GrantType") @@ -17,23 +25,32 @@ func Code2Session(js_code string) (string, error) { // 创建一个新的HTTP请求 req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { - return "", fmt.Errorf("error creating request: %v", err) + return nil, fmt.Errorf("error creating request: %v", err) } // 发送HTTP请求 client := &http.Client{} resp, err := client.Do(req) if err != nil { - return "", fmt.Errorf("error sending request: %v", err) + return nil, fmt.Errorf("error sending request: %v", err) } defer resp.Body.Close() // 读取响应体 body, err := io.ReadAll(resp.Body) if err != nil { - return "", fmt.Errorf("error reading response body: %v", err) + return nil, fmt.Errorf("error reading response body: %v", err) } - // 返回响应体 - return string(body), nil + // 解析响应体。 + var response Response + if err := json.Unmarshal(body, &response); err != nil { + return nil, fmt.Errorf("error parsing response body: %v", err) + } + // check Success + if response.Errcode != 0 { + return nil, fmt.Errorf("error code: %d, error message: %s", response.Errcode, response.Errmsg) + } + + return &response, nil } diff --git a/config/config.yml b/config/config.yml index 136c5a4..f1247a4 100644 --- a/config/config.yml +++ b/config/config.yml @@ -142,10 +142,10 @@ Captcha: captchaValue: "captcha_value" #验证码值提交时的键名 length: 4 # 验证码生成时的长度 -WeixinServer: +Weixin: AppId: "wxe1ff76a57cc6eed3" AppSecret: "46a3557653462da34c6e69f17a472c7c" Code2Session: - grant_type: "authorization_code" # 主要就是想避免硬编码。 + GrantType: "authorization_code" # 主要就是想避免硬编码。 \ No newline at end of file diff --git a/routers/web.go b/routers/web.go index 934f468..e554c9b 100644 --- a/routers/web.go +++ b/routers/web.go @@ -3,10 +3,12 @@ package routers import ( "catface/app/global/consts" "catface/app/global/variable" + // "catface/app/http/controller/captcha" // 验证码组件 // "catface/app/http/middleware/authorization" "catface/app/http/middleware/cors" validatorFactory "catface/app/http/validator/core/factory" + // TODO validatorFactory "catface/app/http/validator/core/factory" "catface/app/utils/gin_release" "net/http" @@ -77,6 +79,7 @@ func InitWebRouter() *gin.Engine { // 【不需要token】中间件验证的路由 用户注册、登录 noAuth := backend.Group("users") { + noAuth.POST("weixinlogin", validatorFactory.Create(consts.ValidatorPrefix+"UsersWeixinLogin")) // 关于路由的第二个参数用法说明 // 1.编写一个表单参数验证器结构体,参见代码: app/http/validator/web/users/register.go // 2.将以上表单参数验证器注册,遵守 键 =》值 格式注册即可 ,app/http/validator/common/register_validator/web_register_validator.go 20行就是注册时候的键 consts.ValidatorPrefix+"UsersRegister"