package exchange import ( "encoding/json" "fmt" "github.com/demdxx/gocast" "strings" "time" ) // doc: https://dsgxajqzhgq3.sg.larksuite.com/wiki/Xxp0wsLKmiZFB3kRqJYl3cqlgHb // 平台授权链接 // 正式环境跳转地址为配置项目 为兼容测试环境/web环境 当无法获得指定跳转地址则使用默认root_url // root_url func AuthRoot() string { return conf().RootUrl } // 测试环境使用 func AuthUrl(redirectUri string, args ...string) string { uri := AuthUri(redirectUri, args...) return ToPath(conf().RootUrl, uri) } func NoDomainAuthUrl(redirectUri string, args ...string) string { realRedirect := conf().RedirectUrl if redirectUri != "" { realRedirect = redirectUri } // 自动跳转 scope=snsapi_base //uri := fmt.Sprintf("/zh-CN/application-center/authorize?scope=snsapi_base&appid=%s&redirect_uri=%s", conf().Appid, realRedirect) uri := fmt.Sprintf("/zh-CN/application-center/authorize?appid=%s&redirect_uri=%s", conf().Appid, realRedirect) if len(args) > 0 { //uri = fmt.Sprintf("/zh-CN/application-center/authorize?scope=snsapi_base&appid=%s&redirect_uri=%s&state=%s", conf().Appid, realRedirect, strings.Join(args, "")) uri = fmt.Sprintf("/zh-CN/application-center/authorize?appid=%s&redirect_uri=%s&state=%s", conf().Appid, realRedirect, strings.Join(args, "")) } return uri } // uri func AuthUri(redirectUri string, args ...string) string { realRedirect := conf().RedirectUrl if redirectUri != "" { realRedirect = redirectUri } // 自动跳转 scope=snsapi_base //uri := fmt.Sprintf("/zh-CN/application-center/authorize?scope=snsapi_base&appid=%s&redirect_uri=%s", conf().Appid, realRedirect) uri := fmt.Sprintf("/zh-CN/application-center/authorize?appid=%s&redirect_uri=%s", conf().Appid, realRedirect) if len(args) > 0 { //uri = fmt.Sprintf("/zh-CN/application-center/authorize?scope=snsapi_base&appid=%s&redirect_uri=%s&state=%s", conf().Appid, realRedirect, strings.Join(args, "")) uri = fmt.Sprintf("/zh-CN/application-center/authorize?appid=%s&redirect_uri=%s&state=%s", conf().Appid, realRedirect, strings.Join(args, "")) } return uri } // ToPath 转化成路径 func ToPath(args ...string) string { if len(args) == 0 { return "" } strList := make([]string, 0) for i, p := range args { if strings.TrimSpace(p) == "" { continue } if i == 0 { strList = append(strList, strings.TrimRight(strings.TrimSpace(p), "/")) continue } strList = append(strList, strings.Trim(strings.TrimSpace(p), "/")) } return strings.Join(strList, "/") } // 通过code换取授权access_token type AccessTokenResp struct { Code int `json:"code"` Msg string `json:"msg"` Data struct { AccessToken string `json:"accessToken"` OpenId string `json:"openId"` NickName string `json:"nickName"` AvatarUrl string `json:"avatarUrl"` RefreshToken string `json:"refreshToken"` UserId int64 `json:"userId"` } `json:"data"` } func AccessToken(code string) (*AccessTokenResp, error) { uri := "/v1/third/open/oauth2/access_token" uri = fmt.Sprintf("%s?appId=%s&appSecret=%s&code=%s", uri, conf().Appid, conf().Secret, code) // get request uri = ToPath(conf().RootUrl, uri) return get[AccessTokenResp](uri) } type GetUserInfoReq struct { AppId string `json:"appId"` //OpenId string `json:"openId"` UserId string `json:"userId"` Timestamp string `json:"timestamp"` Sign string `json:"sign"` } type ExchangeUserInfo struct { InviteCode string `json:"inviteCode"` ParentInviteCode string `json:"parentInviteCode"` ParentUserId int64 `json:"parentUserId"` } type UserInfoResp struct { Code int `json:"code"` Msg string `json:"msg"` Data *ExchangeUserInfo `json:"data"` } func GetUserInviteInfo(userID string) (*ExchangeUserInfo, error) { uri := "/v1/act/public/application/third/invite-info" url := ToPath(conf().RootUrl, uri) req := &GetUserInfoReq{ AppId: conf().Appid, UserId: userID, Timestamp: fmt.Sprintf("%d", time.Now().UnixMilli()), } reqMap, err := structToJSONMap(req) if err != nil { return nil, err } sign := signMd5(reqMap) req.Sign = sign data, _ := json.Marshal(&req) t, err := post[UserInfoResp](url, data) if err != nil { return nil, err } if t != nil && t.Data != nil && t.Code == 200 { return t.Data, nil } return nil, fmt.Errorf("exchange msg:%s code:%d", t.Msg, t.Code) } // 刷新access_token(如果需要) get type RefreshTokenResp struct { Code int `json:"code"` Msg string `json:"msg"` Data struct { AccessToken string `json:"accessToken"` OpenId string `json:"openId"` RefreshToken string `json:"refreshToken"` } `json:"data"` } func RefreshToken(refreshToken string) (*RefreshTokenResp, error) { uri := "/v1/third/open/oauth2/refresh_token" uri = fmt.Sprintf("%s?appId=%s&refresh_token=%s", uri, conf().Appid, refreshToken) uri = ToPath(conf().RootUrl, uri) return get[RefreshTokenResp](uri) } // 检验access_token是否有效 get type CheckAccessTokenResp struct { Code int `json:"code"` Msg string `json:"msg"` Data bool `json:"data"` } func Auth(token string) (*CheckAccessTokenResp, error) { uri := "/v1/third/open/oauth2/auth" uri = fmt.Sprintf("%s?accessToken=%s", uri, token) uri = ToPath(conf().RootUrl, uri) return get[CheckAccessTokenResp](uri) } // 获取用户推荐码 type UserInviteInfoResp struct { Code int `json:"code"` Msg string `json:"msg"` Data struct { InviteCode string `json:"inviteCode"` } `json:"data"` } // openId 查询邀请码 // 通过openId 获取上级信息 openId 查询邀请码以及上级邀请码和openId // /v1/act/public/application/third/invite-info-by-openid type SignParam struct { AppId string `json:"appId,omitempty"` OpenId string `json:"openId,omitempty"` Timestamp string `json:"timestamp,omitempty"` } type GetUserInviteInfoReq struct { AppId string `json:"appId,omitempty"` OpenId string `json:"openId,omitempty"` Timestamp string `json:"timestamp,omitempty"` Sign string `json:"sign,omitempty"` } type GetInviteInfoByOpenIdResp struct { Code int `json:"code"` Msg string `json:"msg"` Data struct { InviteCode string `json:"inviteCode"` ParentInviteCode string `json:"parentInviteCode"` ParentOpenId string `json:"parentOpenId"` } `json:"data"` } func GetInviteInfoByOpenId(openId string) (*GetInviteInfoByOpenIdResp, error) { uri := "/v1/act/public/application/third/invite-info-by-openid" uri = ToPath(conf().RootUrl, uri) timestamp := time.Now().UnixMilli() req := new(GetUserInviteInfoReq) req.Timestamp = gocast.ToString(timestamp) req.AppId = conf().Appid req.OpenId = openId reqMap, err := structToJSONMap(req) if err != nil { return nil, err } sign := signMd5(reqMap) req.Sign = sign data, _ := json.Marshal(&req) return post[GetInviteInfoByOpenIdResp](uri, data) }