Improve UserInfo.

This commit is contained in:
Yang Luo 2021-05-31 00:55:29 +08:00
parent 0960578c35
commit 95cda41732
5 changed files with 143 additions and 123 deletions

View File

@ -153,7 +153,7 @@ func (c *ApiController) Login() {
}
if form.Method == "signup" {
user := object.GetUserByField(application.Organization, provider.Type, userInfo.Username)
user := object.GetUserByField(application.Organization, provider.Type, userInfo.Id)
if user != nil {
//if object.IsForbidden(userId) {
// c.forbiddenAccountResp(userId)
@ -170,7 +170,7 @@ func (c *ApiController) Login() {
//if userId := object.GetUserIdByField(application, "email", userInfo.Email); userId != "" {
// resp = c.HandleLoggedIn(userId, &form)
//
// object.LinkUserAccount(userId, provider.Type, userInfo.Username)
// object.LinkUserAccount(userId, provider.Type, userInfo.Id)
//}
if !application.EnableSignUp {
@ -201,15 +201,12 @@ func (c *ApiController) Login() {
if userInfo.Username != "" {
propertyName := fmt.Sprintf("oauth_%s_username", provider.Type)
object.SetUserProperty(user, propertyName, userInfo.Username)
if user.DisplayName == "" {
object.SetUserField(user, "display_name", userInfo.Username)
}
}
if userInfo.AvatarUrl != "" {
propertyName := fmt.Sprintf("oauth_%s_avatarUrl", provider.Type)
object.SetUserProperty(user, propertyName, userInfo.AvatarUrl)
if user.Avatar == "" {
object.SetUserField(user, "avatar", userInfo.AvatarUrl)
if userInfo.DisplayName != "" {
propertyName := fmt.Sprintf("oauth_%s_displayname", provider.Type)
object.SetUserProperty(user, propertyName, userInfo.DisplayName)
if user.DisplayName == "" {
object.SetUserField(user, "display_name", userInfo.DisplayName)
}
}
if userInfo.Email != "" {
@ -219,8 +216,15 @@ func (c *ApiController) Login() {
object.SetUserField(user, "email", userInfo.Email)
}
}
if userInfo.AvatarUrl != "" {
propertyName := fmt.Sprintf("oauth_%s_avatarUrl", provider.Type)
object.SetUserProperty(user, propertyName, userInfo.AvatarUrl)
if user.Avatar == "" {
object.SetUserField(user, "avatar", userInfo.AvatarUrl)
}
}
isLinked := object.LinkUserAccount(user, provider.Type, userInfo.Username)
isLinked := object.LinkUserAccount(user, provider.Type, userInfo.Id)
if isLinked {
resp = &Response{Status: "ok", Msg: "", Data: isLinked}
} else {

View File

@ -19,7 +19,7 @@ import (
"encoding/json"
"io/ioutil"
"net/http"
"sync"
"strconv"
"time"
"golang.org/x/oauth2"
@ -65,42 +65,6 @@ func (idp *GithubIdProvider) GetToken(code string) (*oauth2.Token, error) {
return idp.Config.Exchange(ctx, code)
}
func (idp *GithubIdProvider) getEmail(token *oauth2.Token) string {
res := ""
type GithubEmail struct {
Email string `json:"email"`
Primary bool `json:"primary"`
Verified bool `json:"verified"`
Visibility string `json:"visibility"`
}
var githubEmails []GithubEmail
req, err := http.NewRequest("GET", "https://api.github.com/user/emails", nil)
if err != nil {
panic(err)
}
req.Header.Add("Authorization", "token "+token.AccessToken)
response, err := idp.Client.Do(req)
if err != nil {
panic(err)
}
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
err = json.Unmarshal(contents, &githubEmails)
if err != nil {
panic(err)
}
for _, v := range githubEmails {
if v.Primary == true {
res = v.Email
break
}
}
return res
}
//{
// "login": "jimgreen",
// "id": 3781234,
@ -195,9 +159,7 @@ type GitHubUserInfo struct {
} `json:"plan"`
}
func (idp *GithubIdProvider) getLoginAndAvatar(token *oauth2.Token) (string, string) {
var githubUserInfo GitHubUserInfo
func (idp *GithubIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
req, err := http.NewRequest("GET", "https://api.github.com/user", nil)
if err != nil {
panic(err)
@ -205,38 +167,28 @@ func (idp *GithubIdProvider) getLoginAndAvatar(token *oauth2.Token) (string, str
req.Header.Add("Authorization", "token "+token.AccessToken)
resp, err := idp.Client.Do(req)
if err != nil {
panic(err)
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
return nil, err
}
var githubUserInfo GitHubUserInfo
err = json.Unmarshal(body, &githubUserInfo)
if err != nil {
panic(err)
return nil, err
}
return githubUserInfo.Login, githubUserInfo.AvatarUrl
}
func (idp *GithubIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
userInfo := &UserInfo{}
var wg sync.WaitGroup
wg.Add(2)
go func() {
userInfo.Email = idp.getEmail(token)
wg.Done()
}()
go func() {
userInfo.Username, userInfo.AvatarUrl = idp.getLoginAndAvatar(token)
wg.Done()
}()
wg.Wait()
return userInfo, nil
userInfo := UserInfo{
Id: strconv.Itoa(githubUserInfo.Id),
Username: githubUserInfo.Login,
DisplayName: githubUserInfo.Name,
Email: githubUserInfo.Email,
AvatarUrl: githubUserInfo.AvatarUrl,
}
return &userInfo, nil
}

View File

@ -111,7 +111,8 @@ func (idp *GoogleIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
}
userInfo := UserInfo{
Username: googleUserInfo.Id,
Id: googleUserInfo.Id,
Username: googleUserInfo.Email,
DisplayName: googleUserInfo.Name,
Email: googleUserInfo.Email,
AvatarUrl: googleUserInfo.Picture,

View File

@ -68,8 +68,8 @@ func (idp *QqIdProvider) GetToken(code string) (*oauth2.Token, error) {
params.Add("code", code)
params.Add("redirect_uri", idp.Config.RedirectURL)
getAccessTokenUrl := fmt.Sprintf("https://graph.qq.com/oauth2.0/token?%s", params.Encode())
resp, err := idp.Client.Get(getAccessTokenUrl)
accessTokenUrl := fmt.Sprintf("https://graph.qq.com/oauth2.0/token?%s", params.Encode())
resp, err := idp.Client.Get(accessTokenUrl)
if err != nil {
return nil, err
}
@ -87,9 +87,59 @@ func (idp *QqIdProvider) GetToken(code string) (*oauth2.Token, error) {
return token, nil
}
//{
// "ret": 0,
// "msg": "",
// "is_lost": 0,
// "nickname": "飞翔的企鹅",
// "gender": "男",
// "gender_type": 1,
// "province": "",
// "city": "安道尔城",
// "year": "1968",
// "constellation": "",
// "figureurl": "http:\/\/qzapp.qlogo.cn\/qzapp\/101896710\/C0D022F92B604AA4B1CDF92CC79463A4\/30",
// "figureurl_1": "http:\/\/qzapp.qlogo.cn\/qzapp\/101896710\/C0D022F92B604AA4B1CDF92CC79463A4\/50",
// "figureurl_2": "http:\/\/qzapp.qlogo.cn\/qzapp\/101896710\/C0D022F92B604AA4B1CDF92CC79463A4\/100",
// "figureurl_qq_1": "http://thirdqq.qlogo.cn/g?b=oidb&k=QtAu5OiaSfqGD0kfclwvxJA&s=40&t=1557635654",
// "figureurl_qq_2": "http://thirdqq.qlogo.cn/g?b=oidb&k=QtAu5OiaSfqGD0kfclwvxJA&s=100&t=1557635654",
// "figureurl_qq": "http://thirdqq.qlogo.cn/g?b=oidb&k=QtAu5OiaSfqGD0kfclwvxJA&s=640&t=1557635654",
// "figureurl_type": "1",
// "is_yellow_vip": "0",
// "vip": "0",
// "yellow_vip_level": "0",
// "level": "0",
// "is_yellow_year_vip": "0"
//}
type QqUserInfo struct {
Ret int `json:"ret"`
Msg string `json:"msg"`
IsLost int `json:"is_lost"`
Nickname string `json:"nickname"`
Gender string `json:"gender"`
GenderType int `json:"gender_type"`
Province string `json:"province"`
City string `json:"city"`
Year string `json:"year"`
Constellation string `json:"constellation"`
Figureurl string `json:"figureurl"`
Figureurl1 string `json:"figureurl_1"`
Figureurl2 string `json:"figureurl_2"`
FigureurlQq1 string `json:"figureurl_qq_1"`
FigureurlQq2 string `json:"figureurl_qq_2"`
FigureurlQq string `json:"figureurl_qq"`
FigureurlType string `json:"figureurl_type"`
IsYellowVip string `json:"is_yellow_vip"`
Vip string `json:"vip"`
YellowVipLevel string `json:"yellow_vip_level"`
Level string `json:"level"`
IsYellowYearVip string `json:"is_yellow_year_vip"`
}
func (idp *QqIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
getOpenIdUrl := fmt.Sprintf("https://graph.qq.com/oauth2.0/me?access_token=%s", token.AccessToken)
resp, err := idp.Client.Get(getOpenIdUrl)
openIdUrl := fmt.Sprintf("https://graph.qq.com/oauth2.0/me?access_token=%s", token.AccessToken)
resp, err := idp.Client.Get(openIdUrl)
if err != nil {
return nil, err
}
@ -104,33 +154,32 @@ func (idp *QqIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
return nil, errors.New("openId is empty")
}
getUserInfoUrl := fmt.Sprintf("https://graph.qq.com/user/get_user_info?access_token=%s&oauth_consumer_key=%s&openid=%s", token.AccessToken, idp.Config.ClientID, openId)
resp, err = idp.Client.Get(getUserInfoUrl)
userInfoUrl := fmt.Sprintf("https://graph.qq.com/user/get_user_info?access_token=%s&oauth_consumer_key=%s&openid=%s", token.AccessToken, idp.Config.ClientID, openId)
resp, err = idp.Client.Get(userInfoUrl)
if err != nil {
return nil, err
}
type response struct {
Ret int `json:"ret"`
Nickname string `json:"nickname"`
AvatarUrl string `json:"figureurl_qq_1"`
}
defer resp.Body.Close()
userInfoContent, err := ioutil.ReadAll(resp.Body)
var userResponse response
err = json.Unmarshal(userInfoContent, &userResponse)
userInfoBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if userResponse.Ret != 0 {
return nil, errors.New(fmt.Sprintf("ret expected 0, got %d", userResponse.Ret))
var qqUserInfo QqUserInfo
err = json.Unmarshal(userInfoBody, &qqUserInfo)
if err != nil {
return nil, err
}
if qqUserInfo.Ret != 0 {
return nil, errors.New(fmt.Sprintf("ret expected 0, got %d", qqUserInfo.Ret))
}
userInfo := UserInfo{
Username: openId,
DisplayName: userResponse.Nickname,
AvatarUrl: userResponse.AvatarUrl,
Id: openId,
DisplayName: qqUserInfo.Nickname,
AvatarUrl: qqUserInfo.FigureurlQq1,
}
return &userInfo, nil
}

View File

@ -31,27 +31,6 @@ type WeChatIdProvider struct {
Config *oauth2.Config
}
type WechatAccessToken struct {
AccessToken string `json:"access_token"` //Interface call credentials
ExpiresIn int64 `json:"expires_in"` //access_token interface call credential timeout time, unit (seconds)
RefreshToken string `json:"refresh_token"` //User refresh access_token
Openid string `json:"openid"` //Unique ID of authorized user
Scope string `json:"scope"` //The scope of user authorization, separated by commas. (,)
Unionid string `json:"unionid"` //This field will appear if and only if the website application has been authorized by the user's UserInfo.
}
type WechatUserInfo struct {
Openid string `json:"openid"` //The ID of an ordinary user, which is unique to the current developer account
Nickname string `json:"nickname"` //Ordinary user nickname
Sex int `json:"sex"` //Ordinary user gender, 1 is male, 2 is female
Province string `json:"province"` //Province filled in by ordinary user's personal information
City string `json:"city"` //City filled in by general user's personal data
Country string `json:"country"` //Country, such as China is CN
Headimgurl string `json:"headimgurl"` //User avatar, the last value represents the size of the square avatar (there are optional values of 0, 46, 64, 96, 132, 0 represents a 640*640 square avatar), this item is empty when the user does not have a avatar
Privilege []string `json:"privilege"` //User Privilege information, json array, such as Wechat Woka user (chinaunicom)
Unionid string `json:"unionid"` //Unified user identification. For an application under a WeChat open platform account, the unionid of the same user is unique.
}
func NewWeChatIdProvider(clientId string, clientSecret string, redirectUrl string) *WeChatIdProvider {
idp := &WeChatIdProvider{}
@ -82,6 +61,15 @@ func (idp *WeChatIdProvider) getConfig(clientId string, clientSecret string, red
return config
}
type WechatAccessToken struct {
AccessToken string `json:"access_token"` //Interface call credentials
ExpiresIn int64 `json:"expires_in"` //access_token interface call credential timeout time, unit (seconds)
RefreshToken string `json:"refresh_token"` //User refresh access_token
Openid string `json:"openid"` //Unique ID of authorized user
Scope string `json:"scope"` //The scope of user authorization, separated by commas. (,)
Unionid string `json:"unionid"` //This field will appear if and only if the website application has been authorized by the user's UserInfo.
}
// GetToken use code get access_token (*operation of getting code ought to be done in front)
// get more detail via: https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
func (idp *WeChatIdProvider) GetToken(code string) (*oauth2.Token, error) {
@ -91,8 +79,8 @@ func (idp *WeChatIdProvider) GetToken(code string) (*oauth2.Token, error) {
params.Add("secret", idp.Config.ClientSecret)
params.Add("code", code)
getAccessTokenUrl := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?%s", params.Encode())
tokenResponse, err := idp.Client.Get(getAccessTokenUrl)
accessTokenUrl := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?%s", params.Encode())
tokenResponse, err := idp.Client.Get(accessTokenUrl)
if err != nil {
return nil, err
}
@ -129,6 +117,32 @@ func (idp *WeChatIdProvider) GetToken(code string) (*oauth2.Token, error) {
return &token, nil
}
//{
// "openid": "of_Hl5zVpyj0vwzIlAyIlnXe1234",
// "nickname": "飞翔的企鹅",
// "sex": 1,
// "language": "zh_CN",
// "city": "Shanghai",
// "province": "Shanghai",
// "country": "CN",
// "headimgurl": "https:\/\/thirdwx.qlogo.cn\/mmopen\/vi_32\/Q0j4TwGTfTK6xc7vGca4KtibJib5dslRianc9VHt9k2N7fewYOl8fak7grRM7nS5V6HcvkkIkGThWUXPjDbXkQFYA\/132",
// "privilege": [],
// "unionid": "oxW9O1VAL8x-zfWP2hrqW9c81234"
//}
type WechatUserInfo struct {
Openid string `json:"openid"` // The ID of an ordinary user, which is unique to the current developer account
Nickname string `json:"nickname"` // Ordinary user nickname
Sex int `json:"sex"` // Ordinary user gender, 1 is male, 2 is female
Language string `json:"language"`
City string `json:"city"` // City filled in by general user's personal data
Province string `json:"province"` // Province filled in by ordinary user's personal information
Country string `json:"country"` // Country, such as China is CN
Headimgurl string `json:"headimgurl"` // User avatar, the last value represents the size of the square avatar (there are optional values of 0, 46, 64, 96, 132, 0 represents a 640*640 square avatar), this item is empty when the user does not have a avatar
Privilege []string `json:"privilege"` // User Privilege information, json array, such as Wechat Woka user (chinaunicom)
Unionid string `json:"unionid"` // Unified user identification. For an application under a WeChat open platform account, the unionid of the same user is unique.
}
// GetUserInfo use WechatAccessToken gotten before return WechatUserInfo
// get more detail via: https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Authorized_Interface_Calling_UnionID.html
func (idp *WeChatIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
@ -136,8 +150,8 @@ func (idp *WeChatIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
accessToken := token.AccessToken
openid := token.Extra("Openid")
getUserInfoUrl := fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s", accessToken, openid)
resp, err := idp.Client.Get(getUserInfoUrl)
userInfoUrl := fmt.Sprintf("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s", accessToken, openid)
resp, err := idp.Client.Get(userInfoUrl)
if err != nil {
return nil, err
}
@ -158,13 +172,13 @@ func (idp *WeChatIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
return nil, err
}
username := wechatUserInfo.Unionid
if username == "" {
username = wechatUserInfo.Openid
id := wechatUserInfo.Unionid
if id == "" {
id = wechatUserInfo.Openid
}
userInfo := UserInfo{
Username: username,
Id: id,
DisplayName: wechatUserInfo.Nickname,
AvatarUrl: wechatUserInfo.Headimgurl,
}