Files
toutoukan/controllers/user/userLogin.go
2025-08-14 03:10:24 +08:00

185 lines
4.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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"
"toutoukan/model/usermodel"
"toutoukan/utill"
)
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
ctx := c.Request.Context()
var username string
var exists bool
query := "SELECT EXISTS(SELECT 1 FROM user_info WHERE uid = ? LIMIT 1)"
err = databaseInit.UserDB.QueryRowContext(ctx, query, openid).Scan(&exists)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "查询用户存在性失败: " + err.Error(),
"code": "10029",
})
return
}
if !exists {
username = generateUsername()
now := time.Now()
insertSQL := `
INSERT INTO user_info (
uid, gender,createdtime, updatedtime,username,telephone
) VALUES (?, ?, ?,?,?,?)
`
_, err := databaseInit.UserDB.ExecContext(
ctx,
insertSQL,
openid, // uid使用微信 openid
2,
now,
now,
username,
phoneInfo.PhoneNumber,
)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"error": "插入新用户失败: " + err.Error(),
"code": "10029",
})
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)
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]
}