Files
junhong_cmp_fiber/pkg/wechat/official_account.go
2026-01-30 17:25:30 +08:00

186 lines
5.1 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 wechat
import (
"context"
"github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"go.uber.org/zap"
)
// OfficialAccountService 微信公众号服务实现
type OfficialAccountService struct {
app *officialAccount.OfficialAccount
logger *zap.Logger
}
// NewOfficialAccountService 创建微信公众号服务
func NewOfficialAccountService(app *officialAccount.OfficialAccount, logger *zap.Logger) *OfficialAccountService {
return &OfficialAccountService{
app: app,
logger: logger,
}
}
// GetUserInfo 通过授权码获取用户基本信息(静默授权)
// 返回 OpenID 和 UnionID如果有
func (s *OfficialAccountService) GetUserInfo(ctx context.Context, code string) (openID, unionID string, err error) {
if code == "" {
return "", "", errors.New(errors.CodeInvalidParam, "授权码不能为空")
}
// 设置为静默授权模式snsapi_base只能获取 OpenID
s.app.OAuth.SetScopes([]string{"snsapi_base"})
user, err := s.app.OAuth.UserFromCode(code)
if err != nil {
s.logger.Error("微信 OAuth 授权失败",
zap.String("code", code),
zap.Error(err),
)
return "", "", errors.Wrap(errors.CodeWechatOAuthFailed, err)
}
if user == nil {
s.logger.Error("微信 OAuth 返回空用户信息", zap.String("code", code))
return "", "", errors.New(errors.CodeWechatOAuthFailed, "获取用户信息失败")
}
openID = user.GetOpenID()
// 从原始数据中获取 UnionID
raw, _ := user.GetRaw()
if raw != nil {
if uid, ok := (*raw)["unionid"].(string); ok {
unionID = uid
}
}
s.logger.Debug("微信 OAuth 授权成功",
zap.String("open_id", openID),
zap.String("union_id", unionID),
)
return openID, unionID, nil
}
// GetUserInfoDetailed 通过授权码获取用户详细信息(用户授权)
// 需要用户点击授权,可以获取昵称、头像等信息
func (s *OfficialAccountService) GetUserInfoDetailed(ctx context.Context, code string) (*UserInfo, error) {
if code == "" {
return nil, errors.New(errors.CodeInvalidParam, "授权码不能为空")
}
// 设置为用户信息授权模式snsapi_userinfo
s.app.OAuth.SetScopes([]string{"snsapi_userinfo"})
user, err := s.app.OAuth.UserFromCode(code)
if err != nil {
s.logger.Error("微信 OAuth 授权失败",
zap.String("code", code),
zap.Error(err),
)
return nil, errors.Wrap(errors.CodeWechatOAuthFailed, err)
}
if user == nil {
s.logger.Error("微信 OAuth 返回空用户信息", zap.String("code", code))
return nil, errors.New(errors.CodeWechatOAuthFailed, "获取用户信息失败")
}
raw, _ := user.GetRaw()
userInfo := &UserInfo{
OpenID: user.GetOpenID(),
}
if raw != nil {
if uid, ok := (*raw)["unionid"].(string); ok {
userInfo.UnionID = uid
}
if nickname, ok := (*raw)["nickname"].(string); ok {
userInfo.Nickname = nickname
}
if headimgurl, ok := (*raw)["headimgurl"].(string); ok {
userInfo.Avatar = headimgurl
}
if sex, ok := (*raw)["sex"].(float64); ok {
userInfo.Sex = int(sex)
}
if province, ok := (*raw)["province"].(string); ok {
userInfo.Province = province
}
if city, ok := (*raw)["city"].(string); ok {
userInfo.City = city
}
if country, ok := (*raw)["country"].(string); ok {
userInfo.Country = country
}
}
s.logger.Debug("微信 OAuth 获取用户详细信息成功",
zap.String("open_id", userInfo.OpenID),
zap.String("nickname", userInfo.Nickname),
)
return userInfo, nil
}
// GetUserInfoByToken 通过 AccessToken 和 OpenID 获取用户详细信息
func (s *OfficialAccountService) GetUserInfoByToken(ctx context.Context, accessToken, openID string) (*UserInfo, error) {
if accessToken == "" || openID == "" {
return nil, errors.New(errors.CodeInvalidParam, "AccessToken 和 OpenID 不能为空")
}
user, err := s.app.OAuth.UserFromToken(accessToken, openID)
if err != nil {
s.logger.Error("通过 Token 获取微信用户信息失败",
zap.String("open_id", openID),
zap.Error(err),
)
return nil, errors.Wrap(errors.CodeWechatUserInfoFailed, err)
}
if user == nil {
s.logger.Error("微信返回空用户信息", zap.String("open_id", openID))
return nil, errors.New(errors.CodeWechatUserInfoFailed, "获取用户信息失败")
}
raw, _ := user.GetRaw()
userInfo := &UserInfo{
OpenID: user.GetOpenID(),
}
if raw != nil {
if uid, ok := (*raw)["unionid"].(string); ok {
userInfo.UnionID = uid
}
if nickname, ok := (*raw)["nickname"].(string); ok {
userInfo.Nickname = nickname
}
if headimgurl, ok := (*raw)["headimgurl"].(string); ok {
userInfo.Avatar = headimgurl
}
if sex, ok := (*raw)["sex"].(float64); ok {
userInfo.Sex = int(sex)
}
if province, ok := (*raw)["province"].(string); ok {
userInfo.Province = province
}
if city, ok := (*raw)["city"].(string); ok {
userInfo.City = city
}
if country, ok := (*raw)["country"].(string); ok {
userInfo.Country = country
}
}
s.logger.Debug("通过 Token 获取微信用户详细信息成功",
zap.String("open_id", userInfo.OpenID),
zap.String("nickname", userInfo.Nickname),
)
return userInfo, nil
}