mirror of
https://github.com/xinliangnote/go-gin-api.git
synced 2024-04-21 12:31:46 +00:00
#12 resubmit middlerware
This commit is contained in:
@@ -13,6 +13,8 @@ const (
|
||||
ParamBindError = 10103
|
||||
AuthorizationError = 10104
|
||||
CallHTTPError = 10105
|
||||
ResubmitError = 10106
|
||||
ResubmitMsg = 10107
|
||||
|
||||
// 模块级错误码 - 用户模块
|
||||
IllegalUserName = 20101
|
||||
@@ -29,6 +31,8 @@ var codeText = map[int]string{
|
||||
ParamBindError: "参数信息有误",
|
||||
AuthorizationError: "签名信息有误",
|
||||
CallHTTPError: "调用第三方 HTTP 接口失败",
|
||||
ResubmitError: "Resubmit Error",
|
||||
ResubmitMsg: "请勿重复提交",
|
||||
|
||||
IllegalUserName: "非法用户名",
|
||||
UserCreateError: "创建用户失败",
|
||||
|
||||
@@ -28,7 +28,7 @@ type authResponse struct {
|
||||
func (h *handler) Auth() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
cfg := configs.Get().JWT
|
||||
tokenString, err := token.New(cfg.Secret).Sign(1, "xinliangnote", time.Hour*cfg.ExpireDuration)
|
||||
tokenString, err := token.New(cfg.Secret).JwtSign(1, "xinliangnote", time.Hour*cfg.ExpireDuration)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package auth
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func AuthHandler(ctx core.Context) (userId int64, userName string, err errno.Error) {
|
||||
func (m *middleware) Jwt(ctx core.Context) (userId int64, userName string, err errno.Error) {
|
||||
auth := ctx.GetHeader("Authorization")
|
||||
if auth == "" {
|
||||
err = errno.NewError(
|
||||
@@ -24,7 +24,7 @@ func AuthHandler(ctx core.Context) (userId int64, userName string, err errno.Err
|
||||
}
|
||||
|
||||
cfg := configs.Get().JWT
|
||||
claims, errParse := token.New(cfg.Secret).Parse(auth)
|
||||
claims, errParse := token.New(cfg.Secret).JwtParse(auth)
|
||||
if errParse != nil {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
@@ -0,0 +1,70 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/token"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (m *middleware) Resubmit() core.HandlerFunc {
|
||||
|
||||
redisKeyPrefix := configs.ProjectName() + ":request-id:"
|
||||
|
||||
return func(c core.Context) {
|
||||
cfg := configs.Get().URLToken
|
||||
|
||||
tokenString, err := token.New(cfg.Secret).UrlSign(c.Path(), c.Method(), c.RequestInputParams())
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ResubmitError,
|
||||
code.Text(code.ResubmitError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
redisKey := redisKeyPrefix + tokenString
|
||||
if !m.cache.Exists(redisKey) {
|
||||
err = m.cache.Set(redisKey, "1", time.Minute*cfg.ExpireDuration)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ResubmitError,
|
||||
code.Text(code.ResubmitError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
redisValue, err := m.cache.Get(redisKey, cache.WithTrace(c.Trace()))
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ResubmitError,
|
||||
code.Text(code.ResubmitError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if redisValue == "1" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ResubmitMsg,
|
||||
code.Text(code.ResubmitMsg)).WithErr(errors.New("resubmit")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/user_service"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/grpc"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ Middleware = (*middleware)(nil)
|
||||
|
||||
type Middleware interface {
|
||||
// i 为了避免被其他包实现
|
||||
i()
|
||||
|
||||
// JWT 中间件
|
||||
Jwt(ctx core.Context) (userId int64, userName string, err errno.Error)
|
||||
|
||||
// Resubmit 中间件
|
||||
Resubmit() core.HandlerFunc
|
||||
}
|
||||
|
||||
type middleware struct {
|
||||
logger *zap.Logger
|
||||
cache cache.Repo
|
||||
grpConn grpc.ClientConn
|
||||
userService user_service.UserService
|
||||
}
|
||||
|
||||
func New(logger *zap.Logger, cache cache.Repo) Middleware {
|
||||
return &middleware{
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *middleware) i() {}
|
||||
@@ -3,7 +3,7 @@ package router
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/controller/demo_handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/controller/user_handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/router/middleware/auth"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/router/middleware"
|
||||
"github.com/xinliangnote/go-gin-api/internal/graph/handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
@@ -33,6 +33,10 @@ func NewHTTPMux(logger *zap.Logger, db db.Repo, cache cache.Repo, grpConn grpc.C
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 中间件
|
||||
middles := middleware.New(logger, cache)
|
||||
|
||||
// graphQL 控制器
|
||||
gqlHandler := handler.New(logger, db, cache)
|
||||
|
||||
gql := mux.Group("/graphql")
|
||||
@@ -41,11 +45,26 @@ func NewHTTPMux(logger *zap.Logger, db db.Repo, cache cache.Repo, grpConn grpc.C
|
||||
gql.POST("/query", gqlHandler.Query())
|
||||
}
|
||||
|
||||
// demo 控制器
|
||||
demoHandler := demo_handler.New(logger, db, cache, grpConn)
|
||||
userHandler := user_handler.New(logger, db, cache)
|
||||
demo := mux.Group("/demo", core.WrapAuthHandler(middles.Jwt)) // 使用 jwt 验证
|
||||
{
|
||||
// 为了演示 Trace ,增加了一些看起来无意义的调试信息和 SQL 信息。
|
||||
demo.GET("/trace", demoHandler.Trace())
|
||||
|
||||
// user_demo CURD
|
||||
user := mux.Group("/user", core.WrapAuthHandler(auth.AuthHandler))
|
||||
// 模拟数据
|
||||
demo.GET("get/:name", core.AliasForRecordMetrics("/demo/get"), demoHandler.Get())
|
||||
demo.POST("post", demoHandler.Post())
|
||||
}
|
||||
|
||||
demoNoAuth := mux.Group("/auth") // 不使用 jwt 验证
|
||||
{
|
||||
demoNoAuth.POST("/get", demoHandler.Auth())
|
||||
}
|
||||
|
||||
// user 控制器
|
||||
userHandler := user_handler.New(logger, db, cache)
|
||||
user := mux.Group("/user", core.WrapAuthHandler(middles.Jwt))
|
||||
{
|
||||
user.POST("/create", userHandler.Create())
|
||||
user.PUT("/update", userHandler.UpdateNickNameByID())
|
||||
@@ -53,22 +72,5 @@ func NewHTTPMux(logger *zap.Logger, db db.Repo, cache cache.Repo, grpConn grpc.C
|
||||
user.GET("/info/:username", core.AliasForRecordMetrics("/user/info"), userHandler.Detail())
|
||||
}
|
||||
|
||||
// auth
|
||||
a := mux.Group("/auth")
|
||||
{
|
||||
a.POST("/get", demoHandler.Auth())
|
||||
}
|
||||
|
||||
// demo
|
||||
d := mux.Group("/demo", core.WrapAuthHandler(auth.AuthHandler)) //使用 auth 验证
|
||||
{
|
||||
// 为了演示 Trace ,增加了一些看起来无意义的调试信息和 SQL 信息。
|
||||
d.GET("/trace", demoHandler.Trace())
|
||||
|
||||
// 模拟数据
|
||||
d.GET("get/:name", core.AliasForRecordMetrics("/demo/get"), demoHandler.Get())
|
||||
d.POST("post", demoHandler.Post())
|
||||
}
|
||||
|
||||
return mux, nil
|
||||
}
|
||||
|
||||
Vendored
+10
@@ -34,6 +34,7 @@ type Repo interface {
|
||||
Expire(key string, ttl time.Duration) bool
|
||||
ExpireAt(key string, ttl time.Time) bool
|
||||
Del(keys ...string) bool
|
||||
Exists(keys ...string) bool
|
||||
Incr(key string, options ...Option) int64
|
||||
Close() error
|
||||
}
|
||||
@@ -148,6 +149,15 @@ func (c *cacheRepo) ExpireAt(key string, ttl time.Time) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
//
|
||||
func (c *cacheRepo) Exists(keys ...string) bool {
|
||||
if len(keys) == 0 {
|
||||
return true
|
||||
}
|
||||
value, _ := c.client.Exists(keys...).Result()
|
||||
return value > 0
|
||||
}
|
||||
|
||||
// Del del some key from redis
|
||||
func (c *cacheRepo) Del(keys ...string) bool {
|
||||
if len(keys) == 0 {
|
||||
|
||||
@@ -120,6 +120,10 @@ type Context interface {
|
||||
Alias() string
|
||||
setAlias(path string)
|
||||
|
||||
// RequestInputParams 获取所有参数
|
||||
RequestInputParams() url.Values
|
||||
// RequestPostFormParams 获取 PostForm 参数
|
||||
RequestPostFormParams() url.Values
|
||||
// Request 获取 Request 对象
|
||||
Request() *http.Request
|
||||
// RawData 获取 Request.Body
|
||||
@@ -326,6 +330,18 @@ func (c *context) setAlias(path string) {
|
||||
}
|
||||
}
|
||||
|
||||
// RequestInputParams 获取所有参数
|
||||
func (c *context) RequestInputParams() url.Values {
|
||||
_ = c.ctx.Request.ParseForm()
|
||||
return c.ctx.Request.Form
|
||||
}
|
||||
|
||||
// RequestPostFormParams 获取 PostForm 参数
|
||||
func (c *context) RequestPostFormParams() url.Values {
|
||||
_ = c.ctx.Request.ParseForm()
|
||||
return c.ctx.Request.PostForm
|
||||
}
|
||||
|
||||
// Request 获取 Request
|
||||
func (c *context) Request() *http.Request {
|
||||
return c.ctx.Request
|
||||
|
||||
Reference in New Issue
Block a user