qnc-server-old/service/user.go

362 lines
9.2 KiB
Go
Raw Normal View History

2024-09-14 10:48:09 +08:00
package service
import (
"context"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/redis/go-redis/v9"
"io"
"log"
"net/http"
"net/url"
"qnc-server/config"
"qnc-server/db"
"qnc-server/model/model"
"qnc-server/model/response"
"sort"
"sync"
"time"
)
type UserService struct {
}
// 全能查小程序Code获取openid Unionid
func (UserService *UserService) RequestWx(code string) (wxResponse response.WxLoginResp, err error) {
// 向微信发出登录请求
baseURL := config.ConfigData.System.WxLoginUrl
// 创建查询参数
params := url.Values{}
params.Add("appid", config.ConfigData.System.WxAppId)
params.Add("secret", config.ConfigData.System.WxSecret)
params.Add("js_code", code)
params.Add("grant_type", "authorization_code")
// 构建完整的请求 URL
requestURL := fmt.Sprintf("%s?%s", baseURL, params.Encode())
// 发送 GET 请求
resp, err := http.Get(requestURL)
if err != nil {
return
}
defer resp.Body.Close()
// 读取响应体
body, err := io.ReadAll(resp.Body)
if err != nil {
return
}
// 将响应体解析为结构体
err = json.Unmarshal(body, &wxResponse)
if err != nil {
return
}
if wxResponse.ErrCode != 0 {
err = errors.New(wxResponse.ErrMsg)
return
}
return
}
// Login 全能查 公众号 获取access_token
func (UserService *UserService) RequestWxH5(code string) (wxH5Response response.WxH5LoginResp, err error) {
// 向微信发出登录请求
baseURL := config.ConfigData.System.WxH5LoginUrl
// 创建查询参数
params := url.Values{}
params.Add("appid", config.ConfigData.System.WxH5AppId)
params.Add("secret", config.ConfigData.System.WxH5Secret)
params.Add("code", code)
params.Add("grant_type", "authorization_code")
// 构建完整的请求 URL
requestURL := fmt.Sprintf("%s?%s", baseURL, params.Encode())
// 发送 GET 请求
resp, err := http.Get(requestURL)
if err != nil {
return
}
defer resp.Body.Close()
// 读取响应体
body, err := io.ReadAll(resp.Body)
if err != nil {
return
}
err = json.Unmarshal(body, &wxH5Response)
if err != nil {
return
}
log.Printf("H5-以Code获取access_token响应%v", wxH5Response)
if wxH5Response.Errcode != 0 {
err = errors.New(wxH5Response.Errmsg)
return
}
return
}
// 刷新token
// access_token 2小时过期
// refresh_token 30天过期
//func (UserService *UserService) RefreshToken(openid string) (err error) {
//
//}
// snsapi_userinfo授权拉取用户信息
func (UserService *UserService) GetSnsUserInfo(accessToken string, openid string) (userinfoResp response.WeChatUserInfoResp, err error) {
//https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
// 向微信发出登录请求
baseURL := config.ConfigData.System.WxH5UserinfoUrl
// 创建查询参数
params := url.Values{}
params.Add("access_token", accessToken)
params.Add("openid", openid)
params.Add("lang", "zh_CN")
// 构建完整的请求 URL
requestURL := fmt.Sprintf("%s?%s", baseURL, params.Encode())
log.Printf("请求url: %s", requestURL)
// 发送 GET 请求
resp, err := http.Get(requestURL)
if err != nil {
return
}
defer resp.Body.Close()
// 读取响应体
body, err := io.ReadAll(resp.Body)
if err != nil {
return
}
err = json.Unmarshal(body, &userinfoResp)
if err != nil {
return
}
log.Printf("H5-snsapi_userinfo授权拉取用户信息响应%v", userinfoResp)
if userinfoResp.Errcode != 0 {
err = errors.New(userinfoResp.Errmsg)
return
}
return
}
// 刷新token
// access_token 2小时过期
// refresh_token 30天过期
//func (UserService *UserService) RefreshToken(openid string) (err error) {
//
//}
// 注册用户,创建
func (UserService *UserService) Register(user model.User, authType model.AuthType, authIdentifier model.AuthIdentifier) (auth model.Authentication, err error) {
err = db.DB.Create(&user).Error
if err != nil {
return
}
auth = model.Authentication{
UserID: user.ID,
AuthType: authType,
OpenID: authIdentifier.OpenID,
UnionID: authIdentifier.UnionID,
Phone: authIdentifier.Phone,
}
err = db.DB.Create(&auth).Error
if err != nil {
return
}
return
}
// MatchingAuthentications配对是否有相交的校验
func (UserService *UserService) MatchingAuthentications(authIdentifier model.AuthIdentifier) (authentications []model.Authentication, err error) {
query := db.DB
if authIdentifier.OpenID != "" {
query = query.Or("open_id = ?", authIdentifier.OpenID)
}
if authIdentifier.UnionID != "" {
query = query.Or("union_id = ?", authIdentifier.UnionID)
}
if authIdentifier.Phone != "" {
query = query.Or("phone = ?", authIdentifier.Phone)
}
err = query.Find(&authentications).Error
return
}
// CreateAuthentications 创建校验
func (UserService *UserService) CreateAuthentications(userid uint, authIdentifier model.AuthIdentifier, AuthType model.AuthType) (authentications model.Authentication, err error) {
authentications = model.Authentication{
UserID: userid,
AuthType: AuthType,
OpenID: authIdentifier.OpenID,
UnionID: authIdentifier.UnionID,
Phone: authIdentifier.Phone,
}
err = db.DB.Create(&authentications).Error
if err != nil {
return
}
return
}
// GetUser 根据openid获取全能查用户记录
func (UserService *UserService) GetUser(id uint) (user *model.User, err error) {
err = db.DB.Where("id = ?", id).First(&user).Error
return
}
// GetUser 根据h5_openid获取全能查用户记录
func (UserService *UserService) GetUserByH5(h5Openid string) (user *model.User, err error) {
err = db.DB.Where("h5_openid = ?", h5Openid).First(&user).Error
return
}
// GetUser 根据unionid获取全能查用户记录
func (UserService *UserService) GetUserByUnionid(unionid string) (user *model.User, err error) {
err = db.DB.Where("unionid = ?", unionid).First(&user).Error
return
}
// GetUser 根据userid获取全能查用户记录
func (UserService *UserService) GetUserByUserid(userid uint) (user *model.User, err error) {
err = db.DB.Where("userid = ?", userid).First(&user).Error
return
}
// CreateUser 创建全能查用户
func (UserService *UserService) CreateUser(user *model.User) (err error) {
err = db.DB.Create(&user).Error
return err
}
// update 按unionid更新用户信息
func (UserService *UserService) UpdateUser(user *model.User) (err error) {
err = db.DB.Save(user).Error
return err
}
// h5 SDK 获取config部分
var (
mutex sync.Mutex
)
var ctx = context.Background()
// GetJsapiTicket 获取JSAPI Ticket
func (UserService *UserService) GetJsapiTicket() (string, error) {
jsapiTicket, err := db.RedisClient.Get(ctx, "JsapiTicket").Result()
if err != nil && !errors.Is(err, redis.Nil) {
return "", err
}
if jsapiTicket != "" {
return jsapiTicket, nil
}
mutex.Lock()
defer mutex.Unlock()
accessToken, err := UserService.getAccessToken()
if err != nil {
return "", err
}
ticket, err := UserService.fetchJsapiTicket(accessToken)
if err != nil {
return "", err
}
log.Printf("获取到新的JsapiTicket%s", ticket)
jsapiTicket = ticket
err = db.RedisClient.Set(ctx, "JsapiTicket", jsapiTicket, 7200*time.Second).Err()
if err != nil {
return "", err
}
return jsapiTicket, nil
}
func (UserService *UserService) getAccessToken() (string, error) {
reqUrl := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", config.ConfigData.System.WxH5AppId, config.ConfigData.System.WxH5Secret)
resp, err := http.Get(reqUrl)
if err != nil {
return "", err
}
defer resp.Body.Close()
var result struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
}
err = json.NewDecoder(resp.Body).Decode(&result)
if err != nil {
return "", err
}
if result.Errcode != 0 {
log.Printf("获取AccessToken错误%s", result.Errmsg)
return "", errors.New(result.Errmsg)
}
return result.AccessToken, nil
}
func (UserService *UserService) fetchJsapiTicket(accessToken string) (string, error) {
reqUrl := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", accessToken)
resp, err := http.Get(reqUrl)
if err != nil {
return "", err
}
defer resp.Body.Close()
var result struct {
Ticket string `json:"ticket"`
ExpiresIn int `json:"expires_in"`
Errcode int `json:"errcode"`
Errmsg string `json:"errmsg"`
}
err = json.NewDecoder(resp.Body).Decode(&result)
if err != nil {
return "", err
}
if result.Errcode != 0 {
log.Printf("获取JsapiTicket错误%s", result.Errmsg)
return "", errors.New(result.Errmsg)
}
return result.Ticket, nil
}
// CreateSignature 创建签名
func (UserService *UserService) CreateSignature(ticket, nonceStr, timestamp, url string) string {
// 将参数按 key=value 格式拼接
params := map[string]string{
"jsapi_ticket": ticket,
"noncestr": nonceStr,
"timestamp": timestamp,
"url": url,
}
// 按照 key 的字典序排序
keys := make([]string, 0, len(params))
for key := range params {
keys = append(keys, key)
}
sort.Strings(keys)
// 拼接成一个字符串
str := ""
for _, key := range keys {
if str != "" {
str += "&"
}
str += fmt.Sprintf("%s=%s", key, params[key])
}
// 对字符串进行 SHA1 加密
h := sha1.New()
h.Write([]byte(str))
return hex.EncodeToString(h.Sum(nil))
}