186 lines
5.1 KiB
Go
186 lines
5.1 KiB
Go
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
|
||
}
|