feat(backend): jwt middleware, login with redis rate limit, /auth/me
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"booklib/internal/auth"
|
||||
"booklib/internal/config"
|
||||
"booklib/internal/redispkg"
|
||||
"booklib/internal/store"
|
||||
)
|
||||
|
||||
type api struct {
|
||||
cfg *config.Config
|
||||
st *store.Store
|
||||
rdb *redispkg.R
|
||||
}
|
||||
|
||||
func err(c *gin.Context, status int, code, msg string) {
|
||||
c.AbortWithStatusJSON(status, gin.H{"error": gin.H{"code": code, "message": msg}})
|
||||
}
|
||||
|
||||
func (a *api) authMw() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
h := c.GetHeader("Authorization")
|
||||
tok, ok := strings.CutPrefix(h, "Bearer ")
|
||||
if !ok {
|
||||
err(c, http.StatusUnauthorized, "unauthorized", "missing bearer token")
|
||||
return
|
||||
}
|
||||
cl, perr := auth.Parse(a.cfg.JWTSecret, tok)
|
||||
if perr != nil {
|
||||
err(c, http.StatusUnauthorized, "unauthorized", "invalid token")
|
||||
return
|
||||
}
|
||||
c.Set("uid", cl.UID)
|
||||
c.Set("role", cl.Role)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func (a *api) adminOnly() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if c.GetString("role") != "admin" {
|
||||
err(c, http.StatusForbidden, "forbidden", "admin only")
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func uid(c *gin.Context) int64 { return c.GetInt64("uid") }
|
||||
func isAdmin(c *gin.Context) bool { return c.GetString("role") == "admin" }
|
||||
Reference in New Issue
Block a user