From ba655a6aba89da728cf05a7e7f445a049f80a28f Mon Sep 17 00:00:00 2001 From: mayiming <1627832236@qq.com> Date: Mon, 11 Aug 2025 00:45:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=94=A8=E6=88=B7=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=A7=A3=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controllers/user/userLogin.go | 95 ++++++++++++++++++++++++++++++++--- model/usermodel/userdata.go | 12 +++++ 2 files changed, 99 insertions(+), 8 deletions(-) diff --git a/controllers/user/userLogin.go b/controllers/user/userLogin.go index acc9a96..5ab1dbc 100644 --- a/controllers/user/userLogin.go +++ b/controllers/user/userLogin.go @@ -1,11 +1,16 @@ package user import ( + "crypto/aes" + "crypto/cipher" + "encoding/base64" "encoding/json" "fmt" "github.com/gin-gonic/gin" + "math/rand" "net/http" "net/url" + "strconv" "time" "toutoukan/config" "toutoukan/init/databaseInit" @@ -60,15 +65,34 @@ func UserLogin(c *gin.Context) { return } - // 到这里登录验证成功,获取到了openid和session_key - // 可以在这里进行后续处理,如: - // 1. 根据openid查询或创建用户 - // 2. 生成自定义登录态(如token)返回给客户端 - // 3. (可选)使用session_key、encryptedData和iv解密用户信息 + //可选)使用session_key、encryptedData和iv解密用户信息 + // 步骤2:解密手机号(复用AES解密函数) + phoneData, err := decryptWxData(wxResp.SessionKey, req.EncryptedData, req.Iv) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "解密失败: " + err.Error()}) + return + } + + // 步骤3:解析为手机号结构体 + var phoneInfo usermodel.WxPhoneInfo + if err := json.Unmarshal(phoneData, &phoneInfo); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "解析手机号失败"}) + return + } + + // 验证水印(确保数据有效性) + if phoneInfo.Watermark.AppID != config.Conf.WxID { + c.JSON(http.StatusForbidden, gin.H{"error": "数据水印验证失败"}) + return + } + + fmt.Println("用户手机号为:", phoneInfo.PhoneNumber) openid := wxResp.OpenID ctx := c.Request.Context() // 获取请求上下文,用于控制数据库操作超时 + var username string + // 1. 查询用户是否存在 var exists bool query := "SELECT EXISTS(SELECT 1 FROM user_info WHERE uid = ? LIMIT 1)" @@ -83,11 +107,12 @@ func UserLogin(c *gin.Context) { // 2. 如果用户不存在,插入新用户 if !exists { + username = generateUsername() now := time.Now() insertSQL := ` INSERT INTO user_info ( - uid, gender,createdtime, updatedtime - ) VALUES (?, ?, ?,?) + uid, gender,createdtime, updatedtime,username,telephone + ) VALUES (?, ?, ?,?,?,?) ` _, err := databaseInit.UserDB.ExecContext( ctx, @@ -96,6 +121,8 @@ func UserLogin(c *gin.Context) { 2, now, // createdtime now, // updatedtime + username, + phoneInfo.PhoneNumber, ) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ @@ -104,6 +131,16 @@ func UserLogin(c *gin.Context) { }) return } + } else { + queryUser := "SELECT username FROM user_info WHERE uid = ? LIMIT 1" + err = databaseInit.UserDB.QueryRowContext(ctx, queryUser, openid).Scan(&username) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "查询用户信息失败: " + err.Error(), + "code": "10030", + }) + return + } } token, err := utill.GenerateJWTAndStore(openid) @@ -112,5 +149,47 @@ func UserLogin(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{"result": "success", "error": nil, "code": "20001", "token": token}) + c.JSON(http.StatusOK, gin.H{"result": "success", "error": nil, "code": "20001", "token": token, + "userinfo": map[string]string{ + "username": username, + "uid": openid, + "telephone": phoneInfo.PhoneNumber, + }, + }) +} + +func generateUsername() string { + // 初始化随机数种子(确保每次运行生成不同随机数) + rand.Seed(time.Now().UnixNano()) + // 生成8位随机数字(范围:10000000-99999999) + randomNum := 10000000 + rand.Intn(90000000) // 8位随机数 + return "用户" + strconv.Itoa(randomNum) +} + +func decryptWxData(sessionKey, encryptedData, iv string) ([]byte, error) { + key, _ := base64.StdEncoding.DecodeString(sessionKey) + data, _ := base64.StdEncoding.DecodeString(encryptedData) + ivBytes, _ := base64.StdEncoding.DecodeString(iv) + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + mode := cipher.NewCBCDecrypter(block, ivBytes) + mode.CryptBlocks(data, data) + + return pkcs7Unpad(data), nil // 返回去除填充后的原始数据 +} + +// 去除PKCS#7填充(微信加密数据使用PKCS#7填充) +func pkcs7Unpad(data []byte) []byte { + if len(data) == 0 { + return nil + } + padding := int(data[len(data)-1]) + if padding > len(data) { + return nil + } + return data[:len(data)-padding] } diff --git a/model/usermodel/userdata.go b/model/usermodel/userdata.go index e091ebc..dd522b6 100644 --- a/model/usermodel/userdata.go +++ b/model/usermodel/userdata.go @@ -15,3 +15,15 @@ type UserData struct { CreatedAt time.Time UpdatedAt time.Time } + +type Watermark struct { + Timestamp int64 `json:"timestamp"` // 时间戳,用于验证数据时效性 + AppID string `json:"appid"` // 小程序AppID,用于验证数据来源 +} + +type WxPhoneInfo struct { + PhoneNumber string `json:"phoneNumber"` // 手机号 + PurePhoneNumber string `json:"purePhoneNumber"` // 不带地区码的手机号(如8613800138000 → 13800138000) + CountryCode string `json:"countryCode"` // 国家码(如86) + Watermark Watermark `json:"watermark"` // 水印(验证有效性) +}