package user import ( "crypto/aes" "crypto/cipher" "encoding/base64" "encoding/json" "errors" "fmt" "math/rand" "net/http" "net/url" "strconv" "time" "toutoukan/init/config" "toutoukan/init/databaseInit" "toutoukan/model/usermodel" "toutoukan/utill/jwt" "github.com/gin-gonic/gin" "gorm.io/gorm" ) const wxLoginURL = "https://api.weixin.qq.com/sns/jscode2session" func UserLogin(c *gin.Context) { fmt.Println("Request Body:", c.Request.Body) var req usermodel.WxLoginM if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } fmt.Println("req:123") fmt.Println(req.EncryptedData) fmt.Println(req.Code) fmt.Println(req.Iv) fmt.Println("使用的appid:", config.Conf.WxID) fmt.Println("使用的secret:", config.Conf.Wxsecret) //----------------发送验证请求 params := url.Values{} params.Add("appid", config.Conf.WxID) params.Add("secret", config.Conf.Wxsecret) params.Add("js_code", req.Code) params.Add("grant_type", "authorization_code") requestURL := fmt.Sprintf("%s?%s", wxLoginURL, params.Encode()) fmt.Println("微信接口请求URL:", requestURL) resp, err := http.Get(fmt.Sprintf("%s?%s", wxLoginURL, params.Encode())) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "调用微信登录接口失败: " + err.Error()}) return } fmt.Println("微信登录返回结果:", resp.Body) defer resp.Body.Close() var wxResp usermodel.WxLoginResponse if err := json.NewDecoder(resp.Body).Decode(&wxResp); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "解析微信登录响应失败: " + err.Error(), "code": "10026"}) return } if wxResp.ErrCode != 0 { c.JSON(http.StatusBadRequest, gin.H{ "error": fmt.Sprintf("微信登录失败: %s (错误码: %d)", wxResp.ErrCode, wxResp.ErrMsg), "code": "10027", }) return } phoneData, err := decryptWxData(wxResp.SessionKey, req.EncryptedData, req.Iv) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "解密失败: " + err.Error()}) return } 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 // 业务逻辑实现 var user UserInfo var username string // 查找用户是否存在 result := databaseInit.UserDB.Where("uid = ?", openid).First(&user) if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { // 用户不存在,创建新用户 username := generateUsername() now := time.Now() newUser := UserInfo{ Uid: openid, Gender: 2, // 这里假设 gender 传 2,可根据实际需求修改 CreatedTime: now, UpdatedTime: now, Username: username, Telephone: phoneInfo.PhoneNumber, // 若还有 password、avatar_url、birthdate、bio 等字段需要赋值,可在此补充 // 比如 Password: "默认密码"(实际中密码应加密存储),AvatarUrl: "默认头像地址" 等 Birthdate: nil, } if err := databaseInit.UserDB.Create(&newUser).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": "插入新用户失败: " + err.Error(), "code": "10029", }) return } username = newUser.Username } else { // 数据库查询错误 c.JSON(http.StatusInternalServerError, gin.H{ "error": "查询用户存在性失败: " + result.Error.Error(), "code": "10029", }) return } } else { // 用户已存在,获取用户名 username = user.Username } token, err := jwt.GenerateJWTAndStore(openid) if err != nil { c.JSON(500, gin.H{"error": "生成令牌失败", "code": "10036"}) return } 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()) randomNum := 10000000 + rand.Intn(90000000) 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 } 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] } // 定义与表结构对应的用户模型 type UserInfo struct { Uid string `gorm:"column:uid;primaryKey"` Telephone string `gorm:"column:telephone"` Password string `gorm:"column:password"` AvatarUrl string `gorm:"column:avatar_url"` Gender int `gorm:"column:gender"` Birthdate *time.Time `gorm:"column:birthdate-date;type:datetime;nullable"` CreatedTime time.Time `gorm:"column:createdtime;type:datetime"` UpdatedTime time.Time `gorm:"column:updatedtime;type:datetime"` Bio string `gorm:"column:bio"` Username string `gorm:"column:username"` } // 自定义表名 func (UserInfo) TableName() string { return "user_info" }