feat: add logout
Co-authored-by: cxy004 <cxy004@qq.com> Co-authored-by: wzt <w.zhongtao@qq.com>
This commit is contained in:
parent
f163768aae
commit
ec660e706e
@ -18,6 +18,14 @@ func main() {
|
||||
Name: "Paul",
|
||||
Email: "i@0x7f.app",
|
||||
},
|
||||
{
|
||||
Name: "cxy004",
|
||||
Email: "cxy004@qq.com",
|
||||
},
|
||||
{
|
||||
Name: "wzt",
|
||||
Email: "w.zhongtao@qq.com",
|
||||
},
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
|
3
go.mod
3
go.mod
@ -7,8 +7,8 @@ require (
|
||||
github.com/gin-contrib/pprof v1.4.0
|
||||
github.com/gin-contrib/zap v0.0.2
|
||||
github.com/gin-gonic/gin v1.8.1
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a
|
||||
github.com/swaggo/gin-swagger v1.5.3
|
||||
@ -29,6 +29,7 @@ require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
|
9
go.sum
9
go.sum
@ -74,10 +74,13 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
|
||||
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
|
||||
@ -124,6 +127,8 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
|
||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
|
||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
@ -299,6 +304,9 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
@ -733,6 +741,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -2,6 +2,7 @@ package user
|
||||
|
||||
import (
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/WHUPRJ/woj-server/internal/service/user"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@ -20,8 +21,7 @@ type createRequest struct {
|
||||
// @Param username formData string true "username"
|
||||
// @Param nickname formData string true "nickname"
|
||||
// @Param password formData string true "password"
|
||||
// @Response 200 {object} e.Response "random string"
|
||||
// @Security Authentication
|
||||
// @Response 200 {object} e.Response "jwt token"
|
||||
// @Router /v1/user/create [post]
|
||||
func (h *handler) Create(c *gin.Context) {
|
||||
req := new(createRequest)
|
||||
@ -37,6 +37,21 @@ func (h *handler) Create(c *gin.Context) {
|
||||
Password: req.Password,
|
||||
}
|
||||
|
||||
id, err := h.userService.Create(createData)
|
||||
e.Pong(c, err, id)
|
||||
u, err := h.userService.Create(createData)
|
||||
if err != e.Success {
|
||||
e.Pong(c, err, nil)
|
||||
return
|
||||
}
|
||||
|
||||
version, err := h.userService.IncrVersion(u.ID)
|
||||
if err != e.Success {
|
||||
e.Pong(c, err, nil)
|
||||
return
|
||||
}
|
||||
claim := &global.Claim{
|
||||
UID: u.ID,
|
||||
Version: version,
|
||||
}
|
||||
token, err := h.jwtService.SignClaim(claim)
|
||||
e.Pong(c, err, token)
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package user
|
||||
|
||||
import (
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/WHUPRJ/woj-server/internal/repo/model"
|
||||
"github.com/WHUPRJ/woj-server/internal/service/user"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
@ -14,8 +13,6 @@ type Handler interface {
|
||||
Create(c *gin.Context)
|
||||
Login(c *gin.Context)
|
||||
// List(c *gin.Context)
|
||||
|
||||
tokenNext(c *gin.Context, user *model.User)
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
@ -32,6 +29,7 @@ func RouteRegister(g *global.Global, group *gin.RouterGroup) {
|
||||
}
|
||||
|
||||
group.POST("/login", app.Login)
|
||||
group.POST("/create", app.jwtService.Handler(), app.Create)
|
||||
group.POST("/create", app.Create)
|
||||
group.POST("/logout", app.jwtService.Handler(), app.Logout)
|
||||
// group.GET("/", app.List)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package user
|
||||
|
||||
import (
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/WHUPRJ/woj-server/internal/repo/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@ -18,7 +19,7 @@ type loginRequest struct {
|
||||
// @Produce json
|
||||
// @Param username formData string true "username"
|
||||
// @Param password formData string true "password"
|
||||
// @Response 200 {object} e.Response "random string"
|
||||
// @Response 200 {object} e.Response "jwt token"
|
||||
// @Router /v1/user/login [post]
|
||||
func (h *handler) Login(c *gin.Context) {
|
||||
req := new(loginRequest)
|
||||
@ -40,5 +41,15 @@ func (h *handler) Login(c *gin.Context) {
|
||||
}
|
||||
|
||||
// sign and return token
|
||||
h.tokenNext(c, user)
|
||||
version, err := h.userService.IncrVersion(user.ID)
|
||||
if err != e.Success {
|
||||
e.Pong(c, err, nil)
|
||||
return
|
||||
}
|
||||
claim := &global.Claim{
|
||||
UID: user.ID,
|
||||
Version: version,
|
||||
}
|
||||
token, err := h.jwtService.SignClaim(claim)
|
||||
e.Pong(c, err, token)
|
||||
}
|
||||
|
26
internal/api/user/logout.go
Normal file
26
internal/api/user/logout.go
Normal file
@ -0,0 +1,26 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Logout
|
||||
// @Summary logout
|
||||
// @Description logout
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce json
|
||||
// @Response 200 {object} e.Response "nil"
|
||||
// @Security Authentication
|
||||
// @Router /v1/user/logout [post]
|
||||
func (h *handler) Logout(c *gin.Context) {
|
||||
claim, exist := c.Get("claim")
|
||||
if !exist {
|
||||
e.Pong(c, e.UserUnauthenticated, nil)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := h.userService.IncrVersion(claim.(*global.Claim).UID)
|
||||
e.Pong(c, err, nil)
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/WHUPRJ/woj-server/internal/repo/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (h *handler) tokenNext(c *gin.Context, user *model.User) {
|
||||
claim := &global.Claim{
|
||||
UID: user.ID,
|
||||
UserName: user.UserName,
|
||||
NickName: user.NickName,
|
||||
}
|
||||
token, err := h.jwtService.SignClaim(claim)
|
||||
e.Pong(c, err, token)
|
||||
}
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/WHUPRJ/woj-server/internal/repo/postgresql"
|
||||
"github.com/WHUPRJ/woj-server/internal/repo/redis"
|
||||
"github.com/WHUPRJ/woj-server/internal/router"
|
||||
"github.com/WHUPRJ/woj-server/internal/service/jwt"
|
||||
"go.uber.org/zap"
|
||||
@ -17,9 +18,13 @@ import (
|
||||
|
||||
func Run(g *global.Global) error {
|
||||
// Setup Database
|
||||
g.Db = new(postgresql.PgRepo)
|
||||
g.Db = new(postgresql.Repo)
|
||||
g.Db.Setup(g)
|
||||
|
||||
// Setup Redis
|
||||
g.Redis = new(redis.Repo)
|
||||
g.Redis.Setup(g)
|
||||
|
||||
// Setup JWT
|
||||
g.Jwt = jwt.NewJwtService(g)
|
||||
|
||||
|
@ -17,9 +17,12 @@ const (
|
||||
TokenSignError Err = 205
|
||||
TokenRevoked Err = 206
|
||||
|
||||
UserNotFound Err = 300
|
||||
UserWrongPassword Err = 301
|
||||
UserDuplicated Err = 302
|
||||
UserNotFound Err = 300
|
||||
UserWrongPassword Err = 301
|
||||
UserDuplicated Err = 302
|
||||
UserUnauthenticated Err = 303
|
||||
|
||||
RedisError Err = 400
|
||||
)
|
||||
|
||||
var msgText = map[Err]string{
|
||||
@ -39,7 +42,10 @@ var msgText = map[Err]string{
|
||||
TokenSignError: "Token Sign Error",
|
||||
TokenRevoked: "Token Revoked",
|
||||
|
||||
UserNotFound: "User Not Found",
|
||||
UserWrongPassword: "User Wrong Password",
|
||||
UserDuplicated: "User Duplicated",
|
||||
UserNotFound: "User Not Found",
|
||||
UserWrongPassword: "User Wrong Password",
|
||||
UserDuplicated: "User Duplicated",
|
||||
UserUnauthenticated: "User Unauthenticated",
|
||||
|
||||
RedisError: "Redis Error",
|
||||
}
|
||||
|
@ -6,9 +6,10 @@ import (
|
||||
)
|
||||
|
||||
type Global struct {
|
||||
Log *zap.Logger
|
||||
Conf *Config
|
||||
Stat *metrics.Metrics
|
||||
Db Repo
|
||||
Jwt JwtService
|
||||
Log *zap.Logger
|
||||
Conf *Config
|
||||
Stat *metrics.Metrics
|
||||
Db Repo
|
||||
Redis Repo
|
||||
Jwt JwtService
|
||||
}
|
||||
|
@ -7,17 +7,15 @@ import (
|
||||
)
|
||||
|
||||
type Claim struct {
|
||||
UID uint `json:"id"`
|
||||
UserName string `json:"user_name"`
|
||||
NickName string `json:"nick_name"`
|
||||
Version int `json:"version"`
|
||||
UID uint `json:"id"`
|
||||
Version int64 `json:"version"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
type JwtService interface {
|
||||
ParseToken(tokenText string) (*Claim, e.Err)
|
||||
SignClaim(claim *Claim) (string, e.Err)
|
||||
// TODO: Validate(claim *Claim) bool
|
||||
Validate(claim *Claim) bool
|
||||
|
||||
Handler() gin.HandlerFunc
|
||||
}
|
||||
|
@ -1,12 +1,7 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Repo interface {
|
||||
Setup(*Global)
|
||||
|
||||
Get() *gorm.DB
|
||||
Get() interface{}
|
||||
Close() error
|
||||
}
|
||||
|
@ -14,18 +14,18 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ global.Repo = (*PgRepo)(nil)
|
||||
var _ global.Repo = (*Repo)(nil)
|
||||
|
||||
type PgRepo struct {
|
||||
type Repo struct {
|
||||
db *gorm.DB
|
||||
log *zap.Logger
|
||||
}
|
||||
|
||||
func (r *PgRepo) Get() *gorm.DB {
|
||||
func (r *Repo) Get() interface{} {
|
||||
return r.db
|
||||
}
|
||||
|
||||
func (r *PgRepo) Close() error {
|
||||
func (r *Repo) Close() error {
|
||||
db, err := r.db.DB()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -33,7 +33,7 @@ func (r *PgRepo) Close() error {
|
||||
return db.Close()
|
||||
}
|
||||
|
||||
func (r *PgRepo) Setup(g *global.Global) {
|
||||
func (r *Repo) Setup(g *global.Global) {
|
||||
r.log = g.Log
|
||||
|
||||
r.log.Info("Connecting to database...")
|
||||
@ -78,14 +78,14 @@ func (r *PgRepo) Setup(g *global.Global) {
|
||||
r.migrateDatabase()
|
||||
}
|
||||
|
||||
func (r *PgRepo) migrateDatabase() {
|
||||
func (r *Repo) migrateDatabase() {
|
||||
r.log.Info("Auto Migrating database...")
|
||||
|
||||
_ = r.db.AutoMigrate(&model.User{})
|
||||
}
|
||||
|
||||
// checkAlive deprecated
|
||||
func (r *PgRepo) checkAlive(retry int) (*sql.DB, error) {
|
||||
func (r *Repo) checkAlive(retry int) (*sql.DB, error) {
|
||||
if retry <= 0 {
|
||||
return nil, errors.New("all retries are used up. failed to connect to database")
|
||||
}
|
||||
|
39
internal/repo/redis/redis.go
Normal file
39
internal/repo/redis/redis.go
Normal file
@ -0,0 +1,39 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ global.Repo = (*Repo)(nil)
|
||||
|
||||
type Repo struct {
|
||||
client *redis.Client
|
||||
log *zap.Logger
|
||||
}
|
||||
|
||||
func (r *Repo) Setup(g *global.Global) {
|
||||
r.log = g.Log
|
||||
|
||||
r.client = redis.NewClient(&redis.Options{
|
||||
Addr: g.Conf.Redis.Address,
|
||||
Password: g.Conf.Redis.Password,
|
||||
DB: g.Conf.Redis.Db,
|
||||
})
|
||||
|
||||
_, err := r.client.Ping(context.Background()).Result()
|
||||
if err != nil {
|
||||
r.log.Fatal("Redis ping failed", zap.Error(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Repo) Get() interface{} {
|
||||
return r.client
|
||||
}
|
||||
|
||||
func (r *Repo) Close() error {
|
||||
return r.client.Close()
|
||||
}
|
@ -8,13 +8,14 @@ import (
|
||||
|
||||
func (s *service) Handler() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
const tokenPrefix = "bearer "
|
||||
tokenHeader := c.GetHeader("Authorization")
|
||||
if tokenHeader == "" || !strings.HasPrefix(strings.ToLower(tokenHeader), "bearer ") {
|
||||
if tokenHeader == "" || !strings.HasPrefix(strings.ToLower(tokenHeader), tokenPrefix) {
|
||||
e.Pong(c, e.TokenEmpty, nil)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
token := tokenHeader[7:]
|
||||
token := tokenHeader[len(tokenPrefix):]
|
||||
|
||||
claim, err := s.ParseToken(token)
|
||||
if err != e.Success {
|
||||
@ -23,11 +24,11 @@ func (s *service) Handler() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: validate claim version
|
||||
// if !s.Validate(claim) {
|
||||
// e.Pong(c, e.TokenRevoked, nil)
|
||||
// c.Abort()
|
||||
// }
|
||||
if !s.Validate(claim) {
|
||||
e.Pong(c, e.TokenRevoked, nil)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("claim", claim)
|
||||
c.Next()
|
||||
|
@ -2,6 +2,7 @@ package jwt
|
||||
|
||||
import (
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@ -9,6 +10,7 @@ var _ global.JwtService = (*service)(nil)
|
||||
|
||||
type service struct {
|
||||
log *zap.Logger
|
||||
redis *redis.Client
|
||||
SigningKey []byte
|
||||
ExpireHour int
|
||||
}
|
||||
@ -16,6 +18,7 @@ type service struct {
|
||||
func NewJwtService(g *global.Global) global.JwtService {
|
||||
return &service{
|
||||
log: g.Log,
|
||||
redis: g.Redis.Get().(*redis.Client),
|
||||
SigningKey: []byte(g.Conf.WebServer.JwtSigningKey),
|
||||
ExpireHour: g.Conf.WebServer.JwtExpireHour,
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
@ -17,7 +18,7 @@ func (s *service) ParseToken(tokenText string) (*global.Claim, e.Err) {
|
||||
|
||||
token, err := jwt.ParseWithClaims(
|
||||
tokenText,
|
||||
&global.Claim{},
|
||||
new(global.Claim),
|
||||
func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
@ -64,3 +65,12 @@ func (s *service) SignClaim(claim *global.Claim) (string, e.Err) {
|
||||
}
|
||||
return ss, e.Success
|
||||
}
|
||||
|
||||
func (s *service) Validate(claim *global.Claim) bool {
|
||||
curVersion, err := s.redis.Get(context.Background(), fmt.Sprintf("Version:%d", claim.UID)).Int64()
|
||||
if err != nil {
|
||||
s.log.Debug("redis.Get error", zap.Error(err))
|
||||
return false
|
||||
}
|
||||
return curVersion == claim.Version
|
||||
}
|
||||
|
@ -14,11 +14,11 @@ type CreateData struct {
|
||||
Password string
|
||||
}
|
||||
|
||||
func (s *service) Create(data *CreateData) (uint, e.Err) {
|
||||
func (s *service) Create(data *CreateData) (*model.User, e.Err) {
|
||||
hashed, err := bcrypt.GenerateFromPassword([]byte(data.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
s.log.Debug("bcrypt error", zap.Error(err), zap.String("password", data.Password))
|
||||
return 0, e.InternalError
|
||||
return nil, e.InternalError
|
||||
}
|
||||
|
||||
user := &model.User{
|
||||
@ -28,12 +28,12 @@ func (s *service) Create(data *CreateData) (uint, e.Err) {
|
||||
IsEnabled: true,
|
||||
}
|
||||
|
||||
if err := s.db.Get().Create(user).Error; err != nil {
|
||||
if err := s.db.Create(user).Error; err != nil {
|
||||
if strings.Contains(err.Error(), "duplicate key") {
|
||||
return 0, e.UserDuplicated
|
||||
return nil, e.UserDuplicated
|
||||
}
|
||||
s.log.Debug("create user error", zap.Error(err), zap.Any("data", data))
|
||||
return 0, e.DatabaseError
|
||||
return nil, e.DatabaseError
|
||||
}
|
||||
return user.ID, e.Success
|
||||
return user, e.Success
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
func (s *service) Login(data *model.User) (*model.User, e.Err) {
|
||||
user := &model.User{UserName: data.UserName}
|
||||
|
||||
err := s.db.Get().Where(user).First(&user).Error
|
||||
err := s.db.Where(user).First(&user).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return user, e.UserNotFound
|
||||
}
|
||||
|
@ -4,24 +4,29 @@ import (
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"github.com/WHUPRJ/woj-server/internal/global"
|
||||
"github.com/WHUPRJ/woj-server/internal/repo/model"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var _ Service = (*service)(nil)
|
||||
|
||||
type Service interface {
|
||||
Create(data *CreateData) (uint, e.Err)
|
||||
Create(data *CreateData) (*model.User, e.Err)
|
||||
Login(data *model.User) (*model.User, e.Err)
|
||||
IncrVersion(id uint) (int64, e.Err)
|
||||
}
|
||||
|
||||
type service struct {
|
||||
log *zap.Logger
|
||||
db global.Repo
|
||||
log *zap.Logger
|
||||
db *gorm.DB
|
||||
redis *redis.Client
|
||||
}
|
||||
|
||||
func NewUserService(g *global.Global) Service {
|
||||
return &service{
|
||||
log: g.Log,
|
||||
db: g.Db,
|
||||
log: g.Log,
|
||||
db: g.Db.Get().(*gorm.DB),
|
||||
redis: g.Redis.Get().(*redis.Client),
|
||||
}
|
||||
}
|
||||
|
17
internal/service/user/version.go
Normal file
17
internal/service/user/version.go
Normal file
@ -0,0 +1,17 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/WHUPRJ/woj-server/internal/e"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (s *service) IncrVersion(id uint) (int64, e.Err) {
|
||||
version, err := s.redis.Incr(context.Background(), fmt.Sprintf("Version:%d", id)).Result()
|
||||
if err != nil {
|
||||
s.log.Debug("redis.Incr error", zap.Error(err))
|
||||
return -1, e.RedisError
|
||||
}
|
||||
return version, e.Success
|
||||
}
|
Loading…
Reference in New Issue
Block a user