持久化Token

This commit is contained in:
奶爸 2019-12-20 23:58:09 +08:00
parent af146872fe
commit 70f0e92343
13 changed files with 82 additions and 55 deletions

View File

@ -26,18 +26,17 @@ func (cp *commonPage) serve() {
}
func (cp *commonPage) home(c *gin.Context) {
var admin *model.User
isLogin, ok := c.Get(model.CtxKeyIsUserLogin)
if ok && isLogin.(bool) {
admin = dao.Admin
}
dao.ServerLock.RLock()
defer dao.ServerLock.RUnlock()
c.HTML(http.StatusOK, "page/home", mygin.CommonEnvironment(c, gin.H{
"Admin": admin,
data := gin.H{
"Domain": dao.Conf.Site.Domain,
"Servers": dao.ServerList,
}))
}
u, ok := c.Get(model.CtxKeyAuthorizedUser)
if ok {
data["Admin"] = u
}
c.HTML(http.StatusOK, "page/home", mygin.CommonEnvironment(c, data))
}
var upgrader = websocket.Upgrader{}

View File

@ -28,14 +28,16 @@ func (ma *memberAPI) serve() {
}))
mr.POST("/logout", ma.logout)
mr.POST("/server", ma.addServer)
mr.POST("/server", ma.addOrEditServer)
}
type serverForm struct {
ID uint64
Name string `binding:"required"`
}
func (ma *memberAPI) addServer(c *gin.Context) {
func (ma *memberAPI) addOrEditServer(c *gin.Context) {
admin := c.MustGet(model.CtxKeyAuthorizedUser).(*model.User)
var sf serverForm
var s model.Server
err := c.ShouldBindJSON(&sf)
@ -43,9 +45,13 @@ func (ma *memberAPI) addServer(c *gin.Context) {
dao.ServerLock.Lock()
defer dao.ServerLock.Unlock()
s.Name = sf.Name
s.Secret = com.MD5(fmt.Sprintf("%s%s%d", time.Now(), sf.Name, dao.Admin.ID))
}
if sf.ID == 0 {
s.Secret = com.MD5(fmt.Sprintf("%s%s%d", time.Now(), sf.Name, admin.ID))
s.Secret = s.Secret[:10]
err = dao.DB.Create(&s).Error
} else {
err = dao.DB.Save(&s).Error
}
if err != nil {
c.JSON(http.StatusOK, model.Response{
@ -65,6 +71,7 @@ type logoutForm struct {
}
func (ma *memberAPI) logout(c *gin.Context) {
admin := c.MustGet(model.CtxKeyAuthorizedUser).(*model.User)
var lf logoutForm
if err := c.ShouldBindJSON(&lf); err != nil {
c.JSON(http.StatusOK, model.Response{
@ -73,15 +80,17 @@ func (ma *memberAPI) logout(c *gin.Context) {
})
return
}
if lf.ID != dao.Admin.ID {
if lf.ID != admin.ID {
c.JSON(http.StatusOK, model.Response{
Code: http.StatusBadRequest,
Message: fmt.Sprintf("请求错误:%s", "用户ID不匹配"),
})
return
}
dao.Admin.Token = ""
dao.Admin.TokenExpired = time.Now()
dao.DB.Model(admin).UpdateColumns(model.User{
Token: "",
TokenExpired: time.Now(),
})
c.JSON(http.StatusOK, model.Response{
Code: http.StatusOK,
})

View File

@ -75,9 +75,9 @@ func (oa *oauth2controller) callback(c *gin.Context) {
return
}
user := model.NewUserFromGitHub(gu)
dao.Admin = &user
dao.Admin.IssueNewToken()
c.SetCookie(dao.Conf.Site.CookieName, dao.Admin.Token, 60*60*24*14, "", "", false, false)
user.IssueNewToken()
dao.DB.Save(&user)
c.SetCookie(dao.Conf.Site.CookieName, user.Token, 60*60*24*14, "", "", false, false)
c.Status(http.StatusOK)
c.Writer.WriteString("<script>window.location.href='/'</script>")
}

View File

@ -17,13 +17,11 @@ import (
func init() {
var err error
dao.ServerList = make(map[string]*model.Server)
dao.Conf, err = model.ReadInConfig("data/config.yaml")
dao.Conf = &model.Config{}
err = dao.Conf.Read("data/config.yaml")
if err != nil {
panic(err)
}
dao.Admin = &model.User{
Login: dao.Conf.GitHub.Admin,
}
dao.DB, err = gorm.Open("sqlite3", "data/sqlite.db")
if err != nil {
panic(err)
@ -36,7 +34,7 @@ func init() {
}
func initDB() {
dao.DB.AutoMigrate(model.Server{})
dao.DB.AutoMigrate(model.Server{}, model.User{})
// load cache
var servers []model.Server
dao.DB.Find(&servers)

2
go.mod
View File

@ -22,7 +22,5 @@ require (
github.com/spf13/viper v1.6.1
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 // indirect
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 // indirect
google.golang.org/grpc v1.25.1
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc // indirect
)

View File

@ -2,8 +2,8 @@ package model
import "time"
// CtxKeyIsUserLogin ..
const CtxKeyIsUserLogin = "ckiul"
// CtxKeyAuthorizedUser ..
const CtxKeyAuthorizedUser = "ckau"
// CtxKeyOauth2State ..
const CtxKeyOauth2State = "cko2s"

View File

@ -1,6 +1,8 @@
package model
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
@ -18,26 +20,29 @@ type Config struct {
ClientID string
ClientSecret string
}
v *viper.Viper
}
// ReadInConfig ..
func ReadInConfig(path string) (*Config, error) {
viper.SetConfigFile(path)
err := viper.ReadInConfig()
func (c *Config) Read(path string) error {
c.v = viper.New()
c.v.SetConfigFile(path)
err := c.v.ReadInConfig()
if err != nil {
return nil, err
}
var c Config
err = viper.Unmarshal(&c)
if err != nil {
return nil, err
return err
}
viper.OnConfigChange(func(in fsnotify.Event) {
viper.Unmarshal(&c)
err = c.v.Unmarshal(c)
if err != nil {
return err
}
c.v.OnConfigChange(func(in fsnotify.Event) {
fmt.Println("配置文件更新,重载配置")
c.v.Unmarshal(c)
})
go viper.WatchConfig()
return &c, nil
go c.v.WatchConfig()
return nil
}

View File

@ -48,5 +48,5 @@ func NewUserFromGitHub(gu *github.User) User {
// IssueNewToken ...
func (u *User) IssueNewToken() {
u.Token = com.MD5(fmt.Sprintf("%d%d%s", time.Now().UnixNano(), u.ID, u.Login))
u.TokenExpired = time.Now().AddDate(0, 0, 14)
u.TokenExpired = time.Now().AddDate(0, 2, 0)
}

View File

@ -2,6 +2,7 @@ package mygin
import (
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
@ -24,6 +25,7 @@ type AuthorizeOption struct {
func Authorize(opt AuthorizeOption) func(*gin.Context) {
return func(c *gin.Context) {
token, err := c.Cookie(dao.Conf.Site.CookieName)
token = strings.TrimSpace(token)
var code uint64 = http.StatusForbidden
if opt.Guest {
code = http.StatusBadRequest
@ -35,12 +37,18 @@ func Authorize(opt AuthorizeOption) func(*gin.Context) {
Link: opt.Redirect,
Btn: opt.Btn,
}
var isLogin bool
if err == nil {
isLogin = token == dao.Admin.Token && dao.Admin.Token != "" &&
dao.Admin.TokenExpired.After(time.Now())
if token != "" {
}
var isLogin bool
var u model.User
err = dao.DB.Where("token = ?", token).First(&u).Error
if err == nil {
isLogin = u.TokenExpired.After(time.Now())
}
if isLogin {
c.Set(model.CtxKeyAuthorizedUser, &u)
}
c.Set(model.CtxKeyIsUserLogin, isLogin)
// 已登录且只能游客访问
if isLogin && opt.Guest {
ShowErrorPage(c, commonErr, opt.IsPage)

View File

@ -20,9 +20,9 @@ func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H {
} else {
data["Title"] = fmt.Sprintf("%s - %s", t, dao.Conf.Site.Brand)
}
isLogin, ok := c.Get(model.CtxKeyIsUserLogin)
if ok && isLogin.(bool) {
data["Admin"] = dao.Admin
u, ok := c.Get(model.CtxKeyAuthorizedUser)
if ok {
data["Admin"] = u
}
return data
}

View File

@ -153,8 +153,10 @@
}
// 刷新进度条
bars.forEach((b, i) => {
b.progress('set total', i == 0 ? 100 : b[0].dataset.total);
b.progress('update progress', b[0].dataset.value);
if (b[0] && b[0].dataset) {
b.progress('set total', i == 0 ? 100 : b[0].dataset.total);
b.progress('update progress', b[0].dataset.value);
}
})
}
}

View File

@ -3,7 +3,7 @@
{{template "common/menu" .}}
<div class="nb-container">
<div class="ui container">
<button class="ui right labeled positive icon button" onclick="addServer()"><i class="add icon"></i> 添加服务器
<button class="ui right labeled positive icon button" onclick="addOrEditServer()"><i class="add icon"></i> 添加服务器
</button>
<table class="ui very basic table">
<thead>
@ -11,6 +11,7 @@
<th>ID</th>
<th>备注</th>
<th>密钥</th>
<th>管理</th>
</tr>
</thead>
<tbody>
@ -19,6 +20,16 @@
<td>{{$server.ID}}</td>
<td>{{$server.Name}}</td>
<td>{{$server.Secret}}</td>
<td>
<div class="ui mini icon buttons">
<button class="ui button" onclick="addOrEditServer({{$server}})">
<i class="edit icon"></i>
</button>
<button class="ui button">
<i class="delete icon"></i>
</button>
</div>
</td>
</tr>
{{end}}
</tbody>

View File

@ -19,9 +19,6 @@ var Cache *cache.Cache
// DB ..
var DB *gorm.DB
// Admin ..
var Admin *model.User
// ServerList ..
var ServerList map[string]*model.Server