Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 812212a

Browse files
authored
Merge pull request #133 from lunny/lunny/gitea_login
WIP: Add Gitea Login support
2 parents 3b7f949 + 2b36503 commit 812212a

File tree

11 files changed

+294
-2
lines changed

11 files changed

+294
-2
lines changed

config/env.sample.ini

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ content = 发票,共产党
115115
client_id = xxx
116116
client_secret = xxx
117117

118+
[gitea]
119+
client_id = xxx
120+
client_secret = xxx
121+
118122
[account]
119123
; 是否验证邮箱
120124
verify_email = 0

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/studygolang/studygolang
33
go 1.12
44

55
require (
6+
code.gitea.io/sdk/gitea v0.0.0-20191106151626-e4082d89cc3b
67
github.com/PuerkitoBio/goquery v1.5.0
78
github.com/Unknwon/goconfig v0.0.0-20190425194916-3dba17dd7b9e // indirect
89
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
22
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
33
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
44
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
5+
code.gitea.io/sdk v0.0.0-20191106151626-e4082d89cc3b h1:bAdeOAgzWZ2R8uMTiq4/K0ViBl/j8XGOEok+DciPN9Y=
6+
code.gitea.io/sdk/gitea v0.0.0-20191106151626-e4082d89cc3b h1:T26uiLOnyGHLGvE1+as/j97ceSHk5gt9NgAMaBf/BZw=
7+
code.gitea.io/sdk/gitea v0.0.0-20191106151626-e4082d89cc3b/go.mod h1:8IxkM1gyiwEjfO0m47bcmr3u3foR15+LoVub43hCHd0=
58
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
69
github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk=
710
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=

http/controller/oauth.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ type OAuthController struct{}
2323
func (self OAuthController) RegisterRoute(g *echo.Group) {
2424
g.GET("/oauth/github/callback", self.GithubCallback)
2525
g.GET("/oauth/github/login", self.GithubLogin)
26+
27+
g.GET("/oauth/gitea/callback", self.GiteaCallback)
28+
g.GET("/oauth/gitea/login", self.GiteaLogin)
2629
}
2730

2831
func (OAuthController) GithubLogin(ctx echo.Context) error {
@@ -67,3 +70,46 @@ func (OAuthController) GithubCallback(ctx echo.Context) error {
6770

6871
return ctx.Redirect(http.StatusSeeOther, "/")
6972
}
73+
74+
func (OAuthController) GiteaLogin(ctx echo.Context) error {
75+
uri := ctx.QueryParam("uri")
76+
url := logic.DefaultThirdUser.GiteaAuthCodeUrl(context.EchoContext(ctx), uri)
77+
return ctx.Redirect(http.StatusSeeOther, url)
78+
}
79+
80+
func (OAuthController) GiteaCallback(ctx echo.Context) error {
81+
code := ctx.FormValue("code")
82+
83+
me, ok := ctx.Get("user").(*model.Me)
84+
if ok {
85+
// 已登录用户,绑定 github
86+
logic.DefaultThirdUser.BindGitea(context.EchoContext(ctx), code, me)
87+
88+
redirectURL := ctx.QueryParam("redirect_url")
89+
if redirectURL == "" {
90+
redirectURL = "/account/edit#connection"
91+
}
92+
return ctx.Redirect(http.StatusSeeOther, redirectURL)
93+
}
94+
95+
user, err := logic.DefaultThirdUser.LoginFromGitea(context.EchoContext(ctx), code)
96+
if err != nil || user.Uid == 0 {
97+
var errMsg = ""
98+
if err != nil {
99+
errMsg = err.Error()
100+
} else {
101+
errMsg = "服务内部错误"
102+
}
103+
104+
return render(ctx, "login.html", map[string]interface{}{"error": errMsg})
105+
}
106+
107+
// 登录成功,种cookie
108+
SetLoginCookie(ctx, user.Username)
109+
110+
if user.Balance == 0 {
111+
return ctx.Redirect(http.StatusSeeOther, "/balance")
112+
}
113+
114+
return ctx.Redirect(http.StatusSeeOther, "/")
115+
}

logic/third_user.go

Lines changed: 205 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ package logic
99
import (
1010
"encoding/json"
1111
"errors"
12+
"io/ioutil"
13+
1214
. "github.com/studygolang/studygolang/db"
1315
"github.com/studygolang/studygolang/model"
14-
"io/ioutil"
1516

1617
"github.com/polaris1119/logger"
1718

@@ -21,8 +22,10 @@ import (
2122
)
2223

2324
var githubConf *oauth2.Config
25+
var giteaConf *oauth2.Config
2426

2527
const GithubAPIBaseUrl = "https://api.github.com"
28+
const GiteaAPIBaseUrl = "https://gitea.com/api/v1"
2629

2730
func init() {
2831
githubConf = &oauth2.Config{
@@ -34,6 +37,15 @@ func init() {
3437
TokenURL: "https://github.com/login/oauth/access_token",
3538
},
3639
}
40+
41+
giteaConf = &oauth2.Config{
42+
ClientID: config.ConfigFile.MustValue("gitea", "client_id"),
43+
ClientSecret: config.ConfigFile.MustValue("gitea", "client_secret"),
44+
Endpoint: oauth2.Endpoint{
45+
AuthURL: "https://gitea.com/login/oauth/authorize",
46+
TokenURL: "https://gitea.com/login/oauth/access_token",
47+
},
48+
}
3749
}
3850

3951
type ThirdUserLogic struct{}
@@ -200,6 +212,166 @@ func (self ThirdUserLogic) BindGithub(ctx context.Context, code string, me *mode
200212
return nil
201213
}
202214

215+
func (ThirdUserLogic) GiteaAuthCodeUrl(ctx context.Context, redirectURL string) string {
216+
// Redirect user to consent page to ask for permission
217+
// for the scopes specified above.
218+
giteaConf.RedirectURL = redirectURL
219+
return giteaConf.AuthCodeURL("state", oauth2.AccessTypeOffline)
220+
}
221+
222+
func (self ThirdUserLogic) LoginFromGitea(ctx context.Context, code string) (*model.User, error) {
223+
objLog := GetLogger(ctx)
224+
225+
giteaUser, token, err := self.giteaTokenAndUser(ctx, code)
226+
if err != nil {
227+
objLog.Errorln("LoginFromGithub githubTokenAndUser error:", err)
228+
return nil, err
229+
}
230+
231+
bindUser := &model.BindUser{}
232+
// 是否已经授权过了
233+
_, err = MasterDB.Where("username=? AND type=?", giteaUser.UserName, model.BindTypeGitea).Get(bindUser)
234+
if err != nil {
235+
objLog.Errorln("LoginFromGithub Get BindUser error:", err)
236+
return nil, err
237+
}
238+
239+
if bindUser.Uid > 0 {
240+
// 更新 token 信息
241+
change := map[string]interface{}{
242+
"access_token": token.AccessToken,
243+
"refresh_token": token.RefreshToken,
244+
}
245+
if !token.Expiry.IsZero() {
246+
change["expire"] = int(token.Expiry.Unix())
247+
}
248+
_, err = MasterDB.Table(new(model.BindUser)).Where("uid=?", bindUser.Uid).Update(change)
249+
if err != nil {
250+
objLog.Errorln("LoginFromGithub update token error:", err)
251+
return nil, err
252+
}
253+
254+
user := DefaultUser.FindOne(ctx, "uid", bindUser.Uid)
255+
return user, nil
256+
}
257+
258+
exists := DefaultUser.EmailOrUsernameExists(ctx, giteaUser.Email, giteaUser.UserName)
259+
if exists {
260+
// TODO: 考虑改进?
261+
objLog.Errorln("LoginFromGithub Github 对应的用户信息被占用")
262+
return nil, errors.New("Github 对应的用户信息被占用,可能你注册过本站,用户名密码登录试试!")
263+
}
264+
265+
session := MasterDB.NewSession()
266+
defer session.Close()
267+
session.Begin()
268+
269+
// 有可能获取不到 email?加上 @gitea.com做邮箱后缀
270+
if giteaUser.Email == "" {
271+
giteaUser.Email = giteaUser.UserName + "@gitea.com"
272+
}
273+
// 生成本站用户
274+
user := &model.User{
275+
Email: giteaUser.Email,
276+
Username: giteaUser.UserName,
277+
Name: model.DisplayName(giteaUser),
278+
City: "",
279+
Company: "",
280+
Gitea: giteaUser.UserName,
281+
Website: "",
282+
Avatar: giteaUser.AvatarURL,
283+
IsThird: 1,
284+
Status: model.UserStatusAudit,
285+
}
286+
err = DefaultUser.doCreateUser(ctx, session, user)
287+
if err != nil {
288+
session.Rollback()
289+
objLog.Errorln("LoginFromGithub doCreateUser error:", err)
290+
return nil, err
291+
}
292+
293+
bindUser = &model.BindUser{
294+
Uid: user.Uid,
295+
Type: model.BindTypeGithub,
296+
Email: user.Email,
297+
Tuid: int(giteaUser.ID),
298+
Username: giteaUser.UserName,
299+
Name: model.DisplayName(giteaUser),
300+
AccessToken: token.AccessToken,
301+
RefreshToken: token.RefreshToken,
302+
Avatar: giteaUser.AvatarURL,
303+
}
304+
if !token.Expiry.IsZero() {
305+
bindUser.Expire = int(token.Expiry.Unix())
306+
}
307+
_, err = session.Insert(bindUser)
308+
if err != nil {
309+
session.Rollback()
310+
objLog.Errorln("LoginFromGitea bindUser error:", err)
311+
return nil, err
312+
}
313+
314+
session.Commit()
315+
316+
return user, nil
317+
}
318+
319+
func (self ThirdUserLogic) BindGitea(ctx context.Context, code string, me *model.Me) error {
320+
objLog := GetLogger(ctx)
321+
322+
giteaUser, token, err := self.giteaTokenAndUser(ctx, code)
323+
if err != nil {
324+
objLog.Errorln("LoginFromGitea githubTokenAndUser error:", err)
325+
return err
326+
}
327+
328+
bindUser := &model.BindUser{}
329+
// 是否已经授权过了
330+
_, err = MasterDB.Where("username=? AND type=?", giteaUser.UserName, model.BindTypeGitea).Get(bindUser)
331+
if err != nil {
332+
objLog.Errorln("LoginFromGitea Get BindUser error:", err)
333+
return err
334+
}
335+
336+
if bindUser.Uid > 0 {
337+
// 更新 token 信息
338+
bindUser.AccessToken = token.AccessToken
339+
bindUser.RefreshToken = token.RefreshToken
340+
if !token.Expiry.IsZero() {
341+
bindUser.Expire = int(token.Expiry.Unix())
342+
}
343+
_, err = MasterDB.Where("uid=?", bindUser.Uid).Update(bindUser)
344+
if err != nil {
345+
objLog.Errorln("LoginFromGitea update token error:", err)
346+
return err
347+
}
348+
349+
return nil
350+
}
351+
352+
bindUser = &model.BindUser{
353+
Uid: me.Uid,
354+
Type: model.BindTypeGithub,
355+
Email: giteaUser.Email,
356+
Tuid: int(giteaUser.ID),
357+
Username: giteaUser.UserName,
358+
Name: model.DisplayName(giteaUser),
359+
AccessToken: token.AccessToken,
360+
RefreshToken: token.RefreshToken,
361+
Avatar: giteaUser.AvatarURL,
362+
}
363+
if !token.Expiry.IsZero() {
364+
bindUser.Expire = int(token.Expiry.Unix())
365+
}
366+
_, err = MasterDB.Insert(bindUser)
367+
if err != nil {
368+
objLog.Errorln("LoginFromGitea insert bindUser error:", err)
369+
return err
370+
}
371+
372+
return nil
373+
}
374+
203375
func (ThirdUserLogic) UnBindUser(ctx context.Context, bindId interface{}, me *model.Me) error {
204376
if !DefaultUser.HasPasswd(ctx, me.Uid) {
205377
return errors.New("请先设置密码!")
@@ -243,8 +415,39 @@ func (ThirdUserLogic) githubTokenAndUser(ctx context.Context, code string) (*mod
243415
}
244416

245417
if githubUser.Id == 0 {
246-
return nil, nil, errors.New("get github user info error")
418+
return nil, nil, errors.New("get gitea user info error")
247419
}
248420

249421
return githubUser, token, nil
250422
}
423+
424+
func (ThirdUserLogic) giteaTokenAndUser(ctx context.Context, code string) (*model.GiteaUser, *oauth2.Token, error) {
425+
token, err := giteaConf.Exchange(ctx, code)
426+
if err != nil {
427+
return nil, nil, err
428+
}
429+
430+
httpClient := giteaConf.Client(ctx, token)
431+
resp, err := httpClient.Get(GiteaAPIBaseUrl + "/user")
432+
if err != nil {
433+
return nil, nil, err
434+
}
435+
defer resp.Body.Close()
436+
437+
respBytes, err := ioutil.ReadAll(resp.Body)
438+
if err != nil {
439+
return nil, nil, err
440+
}
441+
442+
giteaUser := &model.GiteaUser{}
443+
err = json.Unmarshal(respBytes, giteaUser)
444+
if err != nil {
445+
return nil, nil, err
446+
}
447+
448+
if giteaUser.ID == 0 {
449+
return nil, nil, errors.New("get gitea user info error")
450+
}
451+
452+
return giteaUser, token, nil
453+
}

model/github_user.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
package model
88

9+
import (
10+
"code.gitea.io/sdk/gitea"
11+
)
12+
913
type GithubUser struct {
1014
Id int `json:"id"`
1115
Login string `json:"login"`
@@ -16,3 +20,12 @@ type GithubUser struct {
1620
Blog string `json:"blog"`
1721
Location string `json:"location"`
1822
}
23+
24+
type GiteaUser = gitea.User
25+
26+
func DisplayName(g *GiteaUser) string {
27+
if g.FullName == "" {
28+
return g.UserName
29+
}
30+
return g.FullName
31+
}

model/user.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ type User struct {
7575
City string `json:"city"`
7676
Company string `json:"company"`
7777
Github string `json:"github"`
78+
Gitea string `json:"gitea"`
7879
Weibo string `json:"weibo"`
7980
Website string `json:"website"`
8081
Monlog string `json:"monlog"`
@@ -177,6 +178,7 @@ type UserRole struct {
177178

178179
const (
179180
BindTypeGithub = iota
181+
BindTypeGitea
180182
)
181183

182184
type BindUser struct {

template/common/layout.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@
198198
<i class="fa fa-github" aria-hidden="true"></i>
199199
GitHub 登录
200200
</a>
201+
<a id="login-gitea" href="/oauth/gitea/login" class="btn btn-default btn-sm pull-left">
202+
<i class="fa fa-github" aria-hidden="true"></i>
203+
Gitea 登录
204+
</a>
201205
<div class="forget">
202206
<a href="/account/forgetpwd" title="点击找回密码">忘记密码?</a>
203207
</div>

template/common/my_info.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ <h3 class="title"><i class="glyphicon glyphicon-user"></i> 用户登录</h3>
9999
<i class="fa fa-github" aria-hidden="true"></i>
100100
GitHub 登录
101101
</a>
102+
<a href="/oauth/gitea/login" class="btn btn-default btn-sm">
103+
<i class="fa fa-github" aria-hidden="true"></i>
104+
Gitea 登录
105+
</a>
102106
</div>
103107
</div>
104108
</form>

0 commit comments

Comments
 (0)