feat: add jwt
This commit is contained in:
@@ -9,6 +9,7 @@ type ServerConfig struct {
|
|||||||
LogPath string `yaml:"logPath"`
|
LogPath string `yaml:"logPath"`
|
||||||
MySQL MySQLConfig `yaml:"mysql"`
|
MySQL MySQLConfig `yaml:"mysql"`
|
||||||
Redis RedisConfig `yaml:"redis"`
|
Redis RedisConfig `yaml:"redis"`
|
||||||
|
Jwt JwtConfig `yaml:"jwt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MySQLConfig struct {
|
type MySQLConfig struct {
|
||||||
@@ -24,3 +25,9 @@ type RedisConfig struct {
|
|||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
Password string `yaml:"password"`
|
Password string `yaml:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type JwtConfig struct {
|
||||||
|
Secret string `yaml:"secret"`
|
||||||
|
RenewExpireDays uint `yaml:"renewExpireDays"`
|
||||||
|
RenewAheadDays uint `yaml:"renewAheadDays"`
|
||||||
|
}
|
||||||
|
|||||||
17
handler/article.go
Normal file
17
handler/article.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"nCovTrack-Backend/models"
|
||||||
|
"nCovTrack-Backend/utils"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SaveArticleHandler(c *gin.Context) {
|
||||||
|
var articleSave models.Article
|
||||||
|
c.ShouldBindJSON(&articleSave)
|
||||||
|
fmt.Println(utils.RenewToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NDMxMDA5MDAsImlhdCI6MTY0MzQyNDkwMH0.L8qNmbHJtV8fiKKxGbkZk3DrKBPdvhie_oFooH5hGOY"))
|
||||||
|
utils.Succ(c, map[string]string{"string": utils.GenerateToken(jwt.MapClaims{})})
|
||||||
|
}
|
||||||
@@ -6,12 +6,13 @@ import (
|
|||||||
|
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initMySQL() {
|
func initMySQL() {
|
||||||
mysqlConf := global.ServerSettings.MySQL
|
mysqlConf := global.ServerSettings.MySQL
|
||||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", mysqlConf.Username, mysqlConf.Password, mysqlConf.Host, mysqlConf.Port, mysqlConf.Database)
|
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", mysqlConf.Username, mysqlConf.Password, mysqlConf.Host, mysqlConf.Port, mysqlConf.Database)
|
||||||
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{NamingStrategy: schema.NamingStrategy{SingularTable: true}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,10 +49,27 @@ func GinRecovery(stack bool) gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
utils.RequestLogError(logParams...)
|
utils.RequestLogError(logParams...)
|
||||||
c.AbortWithStatus(http.StatusInternalServerError)
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
fmt.Println(err)
|
fmt.Printf("\n%s\n", err)
|
||||||
fmt.Printf("\n%s\n", debug.Stack())
|
fmt.Printf("\n%s\n", cutStack(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cutStack(stack []byte) string {
|
||||||
|
stackStr := string(stack)
|
||||||
|
line := 0
|
||||||
|
lastLineCharIndex := 0
|
||||||
|
for index, char := range stackStr {
|
||||||
|
if char == '\n' {
|
||||||
|
line++
|
||||||
|
}
|
||||||
|
if line == 7 {
|
||||||
|
lastLineCharIndex = index + 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(stackStr[lastLineCharIndex:])
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|||||||
16
models/article.go
Normal file
16
models/article.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Article struct {
|
||||||
|
ID int `gorm:"primaryKey;column:id" json:"-"` // 文章id
|
||||||
|
CreateTime time.Time `gorm:"column:create_time" json:"createTime"` // 文章新建时间
|
||||||
|
CreateUser string `gorm:"column:create_user" json:"createUser"` // 文章创建者id
|
||||||
|
ModifyTime time.Time `gorm:"column:modify_time" json:"modifyTime"` // 文章最后更新时间
|
||||||
|
ModifyUser string `gorm:"column:modify_user" json:"modifyUser"` // 文章最后更新者id
|
||||||
|
Title string `gorm:"column:title" json:"title"` // 文章标题
|
||||||
|
Tags string `gorm:"column:tags" json:"tags"` // 文章Tag
|
||||||
|
Resume string `gorm:"column:resume" json:"resume"` // 文章简述
|
||||||
|
Cover string `gorm:"column:cover" json:"cover"` // 文章封面
|
||||||
|
Content string `gorm:"column:content" json:"content"` // 文章内容(如有需要可迁移至对象存储)
|
||||||
|
}
|
||||||
13
router/article.go
Normal file
13
router/article.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"nCovTrack-Backend/global"
|
||||||
|
"nCovTrack-Backend/handler"
|
||||||
|
)
|
||||||
|
|
||||||
|
func articleRouter() {
|
||||||
|
articleRouter := global.RootRouter.Group("/article")
|
||||||
|
{
|
||||||
|
articleRouter.POST("/save", handler.SaveArticleHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,4 +22,5 @@ func BusiRouter() {
|
|||||||
//})
|
//})
|
||||||
}
|
}
|
||||||
statisticRouter()
|
statisticRouter()
|
||||||
|
articleRouter()
|
||||||
}
|
}
|
||||||
|
|||||||
17
service/article/article.go
Normal file
17
service/article/article.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package article
|
||||||
|
|
||||||
|
import (
|
||||||
|
"nCovTrack-Backend/global"
|
||||||
|
"nCovTrack-Backend/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetArticleList() []models.Article {
|
||||||
|
return make([]models.Article, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveArticle(article models.Article) {
|
||||||
|
// 前端校验
|
||||||
|
// articlea := &models.Article{Content: "#Ceshi", Cover: "https://www.baidu.com/link?url=AWfrkr2rXUGVmKuD08cYx7GwAfQw7qXy_ZczQuH9N_raTP0_eRTv4eZgsdYhtMhS8F7nVl9WfdF01byCD5DAKK&wd=&eqid=b50bb6b100004750000000056202107a", Resume: "sss", Tags: "s", Title: "title", CreateUser: "1", ModifyUser: "1", CreateTime: time.Now(), ModifyTime: time.Now()}
|
||||||
|
tx := global.Db.Create(article)
|
||||||
|
print(tx)
|
||||||
|
}
|
||||||
@@ -9,10 +9,15 @@ mysql:
|
|||||||
host: myhost.fallen-angle.com
|
host: myhost.fallen-angle.com
|
||||||
port: 3306
|
port: 3306
|
||||||
username: root
|
username: root
|
||||||
password: 13291004986@lm
|
password: 13291004986
|
||||||
database: nCovTrack
|
database: ncov_track
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
host: myhost.fallen-angle.com
|
host: myhost.fallen-angle.com
|
||||||
port: 6379
|
port: 6379
|
||||||
password: wzl20001001
|
password: wzl20001001
|
||||||
|
|
||||||
|
jwt:
|
||||||
|
secret: bWF5YmVJYWxzb3NhbWV0b2JlZm9yZe
|
||||||
|
renewExpireDays: 7
|
||||||
|
renewAheadDays: 3
|
||||||
|
|||||||
66
utils/jwt.go
Normal file
66
utils/jwt.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"nCovTrack-Backend/global"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
var JWT_KEY = []byte(global.ServerSettings.Jwt.Secret)
|
||||||
|
|
||||||
|
// Generate token for user
|
||||||
|
// Return: token generated
|
||||||
|
func GenerateToken(claims jwt.MapClaims) string {
|
||||||
|
claims["exp"] = time.Now().Add(15 * 24 * time.Hour).Unix()
|
||||||
|
claims["iat"] = time.Now().Unix()
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
tokenStr, err := token.SignedString(JWT_KEY)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return tokenStr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renew user's token
|
||||||
|
// tokenStr: user request token
|
||||||
|
// Return:
|
||||||
|
// BlankString: token is invalid or token is expired out of allowed time;
|
||||||
|
// OldToken: token is not need to renew;
|
||||||
|
// NewToekn: token is renew;
|
||||||
|
func RenewToken(tokenStr string) string {
|
||||||
|
token, err := jwt.Parse(tokenStr, func(t *jwt.Token) (interface{}, error) {
|
||||||
|
return JWT_KEY, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// Token is invalid
|
||||||
|
switch err.(*jwt.ValidationError).Errors {
|
||||||
|
case jwt.ValidationErrorSignatureInvalid:
|
||||||
|
return ""
|
||||||
|
case jwt.ValidationErrorIssuedAt:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
claims := token.Claims.(jwt.MapClaims)
|
||||||
|
expireAt := time.Unix(int64(claims["exp"].(float64)), 0)
|
||||||
|
expireDuration := expireAt.Sub(time.Now())
|
||||||
|
|
||||||
|
// Token is out of allow expire duration
|
||||||
|
if expireDuration.Hours() < float64(-global.ServerSettings.Jwt.RenewExpireDays*24) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// Token not need renew
|
||||||
|
if expireDuration.Hours() > float64(global.ServerSettings.Jwt.RenewAheadDays*24) {
|
||||||
|
return tokenStr
|
||||||
|
}
|
||||||
|
fmt.Println(expireDuration)
|
||||||
|
|
||||||
|
claims["exp"] = time.Now().Add(15 * 24 * time.Hour).Unix()
|
||||||
|
token = jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
tokenStr, err = token.SignedString(JWT_KEY)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return tokenStr
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user