123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- package user
- import (
- "encoding/json"
- "fmt"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- "code.google.com/p/goauth2/oauth"
- "github.com/go-martini/martini"
- "github.com/gogits/gogs/models"
- "github.com/gogits/gogs/modules/base"
- "github.com/gogits/gogs/modules/log"
- "github.com/gogits/gogs/modules/middleware"
- )
- type BasicUserInfo struct {
- Identity string
- Name string
- Email string
- }
- type SocialConnector interface {
- Type() int
- SetRedirectUrl(string)
- UserInfo(*oauth.Token, *url.URL) (*BasicUserInfo, error)
- AuthCodeURL(string) string
- Exchange(string) (*oauth.Token, error)
- }
- func extractPath(next string) string {
- n, err := url.Parse(next)
- if err != nil {
- return "/"
- }
- return n.Path
- }
- var (
- SocialBaseUrl = "/user/login"
- SocialMap = make(map[string]SocialConnector)
- )
- func SocialSignIn(params martini.Params, ctx *middleware.Context) {
- if base.OauthService == nil || !base.OauthService.GitHub.Enabled {
- ctx.Handle(404, "social login not enabled", nil)
- return
- }
- next := extractPath(ctx.Query("next"))
- name := params["name"]
- connect, ok := SocialMap[name]
- if !ok {
- ctx.Handle(404, "social login", nil)
- return
- }
- code := ctx.Query("code")
- if code == "" {
-
- connect.SetRedirectUrl(strings.TrimSuffix(base.AppUrl, "/") + ctx.Req.URL.Host + ctx.Req.URL.Path)
- ctx.Redirect(connect.AuthCodeURL(next))
- return
- }
-
- tk, err := connect.Exchange(code)
- if err != nil {
- log.Error("oauth2 handle callback error: %v", err)
- ctx.Handle(500, "exchange code error", nil)
- return
- }
- next = extractPath(ctx.Query("state"))
- log.Trace("success get token")
- 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)
- return
- }
- log.Info("social login: %s", ui)
- oa, err := models.GetOauth2(ui.Identity)
- switch err {
- case nil:
- ctx.Session.Set("userId", oa.User.Id)
- ctx.Session.Set("userName", oa.User.Name)
- case models.ErrOauth2RecordNotExists:
- oa = &models.Oauth2{}
- raw, _ := json.Marshal(tk)
- oa.Token = string(raw)
- oa.Uid = -1
- oa.Type = connect.Type()
- oa.Identity = ui.Identity
- log.Trace("oa: %v", oa)
- if err = models.AddOauth2(oa); err != nil {
- log.Error("add oauth2 %v", err)
- return
- }
- case models.ErrOauth2NotAssociatedWithUser:
- next = "/user/sign_up"
- default:
- log.Error("other error: %v", err)
- ctx.Handle(500, err.Error(), nil)
- return
- }
- ctx.Session.Set("socialId", oa.Id)
- ctx.Session.Set("socialName", ui.Name)
- ctx.Session.Set("socialEmail", ui.Email)
- log.Trace("socialId: %v", oa.Id)
- ctx.Redirect(next)
- }
- type SocialGithub struct {
- Token *oauth.Token
- *oauth.Transport
- }
- func (s *SocialGithub) Type() int {
- return models.OT_GITHUB
- }
- func init() {
- github := &SocialGithub{}
- name := "github"
- config := &oauth.Config{
- ClientId: "09383403ff2dc16daaa1",
- ClientSecret: "0e4aa0c3630df396cdcea01a9d45cacf79925fea",
- RedirectURL: strings.TrimSuffix(base.AppUrl, "/") + "/user/login/" + name,
- Scope: "https://api.github.com/user",
- AuthURL: "https://github.com/login/oauth/authorize",
- TokenURL: "https://github.com/login/oauth/access_token",
- }
- github.Transport = &oauth.Transport{
- Config: config,
- Transport: http.DefaultTransport,
- }
- SocialMap[name] = github
- }
- func (s *SocialGithub) SetRedirectUrl(url string) {
- s.Transport.Config.RedirectURL = url
- }
- func (s *SocialGithub) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
- transport := &oauth.Transport{
- Token: token,
- }
- var data struct {
- Id int `json:"id"`
- Name string `json:"login"`
- Email string `json:"email"`
- }
- var err error
- r, err := transport.Client().Get(s.Transport.Scope)
- 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: strconv.Itoa(data.Id),
- Name: data.Name,
- Email: data.Email,
- }, nil
- }
- type SocialGoogle struct {
- Token *oauth.Token
- *oauth.Transport
- }
- func (s *SocialGoogle) Type() int {
- return models.OT_GOOGLE
- }
- func init() {
- google := &SocialGoogle{}
- name := "google"
-
-
- config := &oauth.Config{
- ClientId: "849753812404-mpd7ilvlb8c7213qn6bre6p6djjskti9.apps.googleusercontent.com",
- ClientSecret: "VukKc4MwaJUSmiyv3D7ANVCa",
- Scope: "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile",
- AuthURL: "https://accounts.google.com/o/oauth2/auth",
- TokenURL: "https://accounts.google.com/o/oauth2/token",
- }
- google.Transport = &oauth.Transport{
- Config: config,
- Transport: http.DefaultTransport,
- }
- SocialMap[name] = google
- }
- func (s *SocialGoogle) SetRedirectUrl(url string) {
- s.Transport.Config.RedirectURL = url
- }
- func (s *SocialGoogle) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
- transport := &oauth.Transport{Token: token}
- var data struct {
- Id string `json:"id"`
- Name string `json:"name"`
- Email string `json:"email"`
- }
- var err error
- reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
- r, err := transport.Client().Get(reqUrl)
- 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.Id,
- Name: data.Name,
- Email: data.Email,
- }, nil
- }
- 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",
- ClientSecret: "16cd53b8ad2e16a36fc2c8f87d9388f2",
- 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
-
-
-
-
-
- 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
- }
|