@@ -13,6 +13,7 @@ const ( | |||
OT_GITHUB = iota + 1 | |||
OT_GOOGLE | |||
OT_TWITTER | |||
OT_QQ | |||
) | |||
var ( | |||
@@ -28,7 +28,7 @@ type BasicUserInfo struct { | |||
type SocialConnector interface { | |||
Type() int | |||
SetRedirectUrl(string) | |||
UserInfo(*oauth.Token) (*BasicUserInfo, error) | |||
UserInfo(*oauth.Token, *url.URL) (*BasicUserInfo, error) | |||
AuthCodeURL(string) string | |||
Exchange(string) (*oauth.Token, error) | |||
@@ -63,13 +63,13 @@ func SocialSignIn(params martini.Params, ctx *middleware.Context) { | |||
code := ctx.Query("code") | |||
if code == "" { | |||
// redirect to social login page | |||
connect.SetRedirectUrl(strings.TrimSuffix(base.AppUrl, "/") + ctx.Req.URL.RequestURI()) | |||
connect.SetRedirectUrl(strings.TrimSuffix(base.AppUrl, "/") + ctx.Req.URL.Host + ctx.Req.URL.Path) | |||
ctx.Redirect(connect.AuthCodeURL(next)) | |||
return | |||
} | |||
// handle call back | |||
tk, err := connect.Exchange(code) // transport.Exchange(code) | |||
tk, err := connect.Exchange(code) // exchange for token | |||
if err != nil { | |||
log.Error("oauth2 handle callback error: %v", err) | |||
ctx.Handle(500, "exchange code error", nil) | |||
@@ -78,7 +78,7 @@ func SocialSignIn(params martini.Params, ctx *middleware.Context) { | |||
next = extractPath(ctx.Query("state")) | |||
log.Trace("success get token") | |||
ui, err := connect.UserInfo(tk) | |||
ui, err := connect.UserInfo(tk, ctx.Req.URL) | |||
if err != nil { | |||
ctx.Handle(500, fmt.Sprintf("get infomation from %s error: %v", name, err), nil) | |||
log.Error("social connect error: %s", err) | |||
@@ -1,8 +1,13 @@ | |||
// Copyright 2014 The Gogs Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
package user | |||
import ( | |||
"encoding/json" | |||
"net/http" | |||
"net/url" | |||
"strconv" | |||
"strings" | |||
@@ -42,7 +47,7 @@ func (s *SocialGithub) SetRedirectUrl(url string) { | |||
s.Transport.Config.RedirectURL = url | |||
} | |||
func (s *SocialGithub) UserInfo(token *oauth.Token) (*BasicUserInfo, error) { | |||
func (s *SocialGithub) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) { | |||
transport := &oauth.Transport{ | |||
Token: token, | |||
} | |||
@@ -1,8 +1,13 @@ | |||
// Copyright 2014 The Gogs Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
package user | |||
import ( | |||
"encoding/json" | |||
"net/http" | |||
"net/url" | |||
"github.com/gogits/gogs/models" | |||
"code.google.com/p/goauth2/oauth" | |||
@@ -40,7 +45,7 @@ func (s *SocialGoogle) SetRedirectUrl(url string) { | |||
s.Transport.Config.RedirectURL = url | |||
} | |||
func (s *SocialGoogle) UserInfo(token *oauth.Token) (*BasicUserInfo, error) { | |||
func (s *SocialGoogle) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) { | |||
transport := &oauth.Transport{Token: token} | |||
var data struct { | |||
Id string `json:"id"` | |||
@@ -0,0 +1,83 @@ | |||
// Copyright 2014 The Gogs Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
// api reference: http://wiki.open.t.qq.com/index.php/OAuth2.0%E9%89%B4%E6%9D%83/Authorization_code%E6%8E%88%E6%9D%83%E6%A1%88%E4%BE%8B | |||
package user | |||
import ( | |||
"encoding/json" | |||
"net/http" | |||
"net/url" | |||
"github.com/gogits/gogs/models" | |||
"code.google.com/p/goauth2/oauth" | |||
) | |||
type SocialQQ struct { | |||
Token *oauth.Token | |||
*oauth.Transport | |||
reqUrl string | |||
} | |||
func (s *SocialQQ) Type() int { | |||
return models.OT_QQ | |||
} | |||
func init() { | |||
qq := &SocialQQ{} | |||
name := "qq" | |||
config := &oauth.Config{ | |||
ClientId: "801497180", //base.OauthService.GitHub.ClientId, // FIXME: panic when set | |||
ClientSecret: "16cd53b8ad2e16a36fc2c8f87d9388f2", //base.OauthService.GitHub.ClientSecret, | |||
Scope: "all", | |||
AuthURL: "https://open.t.qq.com/cgi-bin/oauth2/authorize", | |||
TokenURL: "https://open.t.qq.com/cgi-bin/oauth2/access_token", | |||
} | |||
qq.reqUrl = "https://open.t.qq.com/api/user/info" | |||
qq.Transport = &oauth.Transport{ | |||
Config: config, | |||
Transport: http.DefaultTransport, | |||
} | |||
SocialMap[name] = qq | |||
} | |||
func (s *SocialQQ) SetRedirectUrl(url string) { | |||
s.Transport.Config.RedirectURL = url | |||
} | |||
func (s *SocialQQ) UserInfo(token *oauth.Token, URL *url.URL) (*BasicUserInfo, error) { | |||
var data struct { | |||
Data struct { | |||
Id string `json:"openid"` | |||
Name string `json:"name"` | |||
Email string `json:"email"` | |||
} `json:"data"` | |||
} | |||
var err error | |||
// https://open.t.qq.com/api/user/info? | |||
//oauth_consumer_key=APP_KEY& | |||
//access_token=ACCESSTOKEN&openid=openid | |||
//clientip=CLIENTIP&oauth_version=2.a | |||
//scope=all | |||
var urls = url.Values{ | |||
"oauth_consumer_key": {s.Transport.Config.ClientId}, | |||
"access_token": {token.AccessToken}, | |||
"openid": URL.Query()["openid"], | |||
"oauth_version": {"2.a"}, | |||
"scope": {"all"}, | |||
} | |||
r, err := http.Get(s.reqUrl + "?" + urls.Encode()) | |||
if err != nil { | |||
return nil, err | |||
} | |||
defer r.Body.Close() | |||
if err = json.NewDecoder(r.Body).Decode(&data); err != nil { | |||
return nil, err | |||
} | |||
return &BasicUserInfo{ | |||
Identity: data.Data.Id, | |||
Name: data.Data.Name, | |||
Email: data.Data.Email, | |||
}, nil | |||
} |