add api middleware

This commit is contained in:
殷勇 2023-09-08 10:38:59 +08:00
parent 9a48d3f673
commit d00e579458
5 changed files with 129 additions and 9 deletions

View File

@ -0,0 +1,64 @@
package api
import (
"errors"
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"main/token"
)
const (
authorizationHeaderKey = "authorization"
authorizationTypeBearer = "bearer"
authorizationTypeBasic = "basic"
authorizationPayloadKey = "authorization_payload"
)
func authMiddleware(tokenMaker token.Maker) gin.HandlerFunc {
return func(ctx *gin.Context) {
authorizationHeader := ctx.GetHeader(authorizationHeaderKey)
if len(authorizationHeader) == 0 {
err := errors.New("authorization header is not provided")
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err))
return
}
fields := strings.Fields(authorizationHeader)
if len(fields) < 2 {
err := errors.New("invalid authorization header format")
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err))
return
}
// Headers key: Authorization
// Headers value: Basic cm9vdDoxMjM0NTY=
authorizationType := strings.ToLower(fields[0])
if authorizationType == authorizationTypeBasic {
user, password, hasAuth := ctx.Request.BasicAuth()
if hasAuth && user == "root" && password == "123456" {
ctx.Next()
return
}
}
if authorizationType != authorizationTypeBearer {
err := fmt.Errorf("unsupported authorization type %s", authorizationType)
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err))
return
}
accessToken := fields[1]
payload, err := tokenMaker.VerifyToken(accessToken)
if err != nil {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errorResponse(err))
return
}
ctx.Set(authorizationPayloadKey, payload)
ctx.Next()
}
}

View File

@ -3,12 +3,14 @@ package api
import (
"github.com/gin-gonic/gin"
"github.com/jmoiron/sqlx"
"main/token"
)
// Server serves HTTP requests for our banking service.
type Server struct {
store *sqlx.DB
router *gin.Engine
store *sqlx.DB
tokenMaker token.Maker
router *gin.Engine
}
func NewServer(store *sqlx.DB) (*Server, error) {
@ -22,14 +24,17 @@ func NewServer(store *sqlx.DB) (*Server, error) {
func (server *Server) setupRouter() {
router := gin.Default()
// Default routers
router.GET("/welcome", server.welcome)
router.POST("/login", server.loginUser)
router.GET("/guilds", server.listGuilds)
router.GET("/guilds/:guild_id", server.getGuild)
router.POST("/guilds", server.createGuild)
router.DELETE("/guilds/:guild_id", server.deleteGuild)
authRoutes := router.Group("/")
// Authentication routers
authRoutes := router.Group("/").Use(authMiddleware(server.tokenMaker))
authRoutes.GET("/accounts", server.listAccounts)
authRoutes.GET("/guilds", server.listGuilds)
authRoutes.GET("/guilds/:guild_id", server.getGuild)
authRoutes.POST("/guilds", server.createGuild)
authRoutes.DELETE("/guilds/:guild_id", server.deleteGuild)
server.router = router
}

View File

@ -63,8 +63,12 @@ type Account struct {
Currency string `json:"currency"`
}
func (server *Server) loginUser(ctx *gin.Context) {
func (server *Server) welcome(ctx *gin.Context) {
ctx.JSON(http.StatusOK, "welcome")
}
func (server *Server) loginUser(ctx *gin.Context) {
ctx.JSON(http.StatusOK, "loginUser")
}
func (server *Server) createAccount(ctx *gin.Context) {

View File

@ -0,0 +1,10 @@
package token
import (
"time"
)
type Maker interface {
CreateToken(username string, duration time.Duration) (string, *Payload, error)
VerifyToken(token string) (*Payload, error)
}

View File

@ -0,0 +1,37 @@
package token
import (
"errors"
"f5"
"time"
)
var (
ErrInvalidToken = errors.New("token is invalid")
ErrExpiredToken = errors.New("token has expired")
)
type Payload struct {
ID int64 `json:"id"`
Username string `json:"username"`
IssuedAt time.Time `json:"issued_at"`
ExpiredAt time.Time `json:"expired_at"`
}
func NewPayload(username string, duration time.Duration) (*Payload, error) {
tokenID := f5.GetApp().NewUuid()
payload := &Payload{
ID: tokenID,
Username: username,
IssuedAt: time.Now(),
ExpiredAt: time.Now().Add(duration),
}
return payload, nil
}
func (payload *Payload) Valid() error {
if time.Now().After(payload.ExpiredAt) {
return ErrExpiredToken
}
return nil
}