diff options
Diffstat (limited to 'routers/user/social.go')
-rw-r--r-- | routers/user/social.go | 140 |
1 files changed, 49 insertions, 91 deletions
diff --git a/routers/user/social.go b/routers/user/social.go index 3e5f69beff..ea47d71b14 100644 --- a/routers/user/social.go +++ b/routers/user/social.go @@ -6,65 +6,32 @@ package user import ( "encoding/json" - "net/http" + "fmt" "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 SocialConnector interface { - Identity() string - Name() string - Email() string - TokenString() string -} - -type SocialGithub struct { - data struct { - Id int `json:"id"` - Name string `json:"login"` - Email string `json:"email"` - } - Token *oauth.Token +type BasicUserInfo struct { + Identity string + Name string + Email string } -func (s *SocialGithub) Identity() string { - return strconv.Itoa(s.data.Id) -} - -func (s *SocialGithub) Name() string { - return s.data.Name -} - -func (s *SocialGithub) Email() string { - return s.data.Email -} - -func (s *SocialGithub) TokenString() string { - data, _ := json.Marshal(s.Token) - return string(data) -} +type SocialConnector interface { + Type() int + SetRedirectUrl(string) + UserInfo(*oauth.Token, *url.URL) (*BasicUserInfo, error) -// Github API refer: https://developer.github.com/v3/users/ -func (s *SocialGithub) Update() error { - scope := "https://api.github.com/user" - transport := &oauth.Transport{ - Token: s.Token, - } - log.Debug("update github info") - r, err := transport.Client().Get(scope) - if err != nil { - return err - } - defer r.Body.Close() - return json.NewDecoder(r.Body).Decode(&s.data) + AuthCodeURL(string) string + Exchange(string) (*oauth.Token, error) } func extractPath(next string) string { @@ -75,85 +42,76 @@ func extractPath(next string) string { return n.Path } -// github && google && ... -func SocialSignIn(ctx *middleware.Context) { - //if base.OauthService != nil && base.OauthService.GitHub.Enabled { - //} +var ( + SocialBaseUrl = "/user/login" + SocialMap = make(map[string]SocialConnector) +) - var socid int64 - var ok bool - next := extractPath(ctx.Query("next")) - log.Debug("social signed check %s", next) - if socid, ok = ctx.Session.Get("socialId").(int64); ok && socid != 0 { - // already login - ctx.Redirect(next) - log.Info("login soc id: %v", socid) +// github && google && ... +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 } - - config := &oauth.Config{ - ClientId: base.OauthService.GitHub.ClientId, - ClientSecret: base.OauthService.GitHub.ClientSecret, - RedirectURL: strings.TrimSuffix(base.AppUrl, "/") + ctx.Req.URL.RequestURI(), - Scope: base.OauthService.GitHub.Scopes, - AuthURL: "https://github.com/login/oauth/authorize", - TokenURL: "https://github.com/login/oauth/access_token", - } - transport := &oauth.Transport{ - Config: config, - Transport: http.DefaultTransport, + 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 == "" { // redirect to social login page - ctx.Redirect(config.AuthCodeURL(next)) + 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 := transport.Exchange(code) + tk, err := connect.Exchange(code) // exchange for token if err != nil { log.Error("oauth2 handle callback error: %v", err) - return // FIXME, need error page 501 + ctx.Handle(500, "exchange code error", nil) + return } next = extractPath(ctx.Query("state")) - log.Debug("success token: %v", tk) + log.Trace("success get token") - gh := &SocialGithub{Token: tk} - if err = gh.Update(); err != nil { - // FIXME: handle error page 501 - log.Error("connect with github error: %s", err) + 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 } - var soc SocialConnector = gh - log.Info("login: %s", soc.Name()) - oa, err := models.GetOauth2(soc.Identity()) + 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) // json encode + oa.Token = string(raw) oa.Uid = -1 - oa.Type = models.OT_GITHUB - oa.Token = soc.TokenString() - oa.Identity = soc.Identity() - log.Debug("oa: %v", oa) + 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) // 501 return } case models.ErrOauth2NotAssociatedWithUser: - ctx.Session.Set("socialId", oa.Id) - ctx.Session.Set("socialName", soc.Name()) - ctx.Session.Set("socialEmail", soc.Email()) - ctx.Redirect("/user/sign_up") - return + next = "/user/sign_up" default: - log.Error(err.Error()) // FIXME: handle error page + log.Error("other error: %v", err) + ctx.Handle(500, err.Error(), nil) return } ctx.Session.Set("socialId", oa.Id) - log.Debug("socialId: %v", oa.Id) + ctx.Session.Set("socialName", ui.Name) + ctx.Session.Set("socialEmail", ui.Email) + log.Trace("socialId: %v", oa.Id) ctx.Redirect(next) } |