feat: access token check
This commit is contained in:
parent
7629f391ad
commit
6786f7ac00
3 changed files with 130 additions and 28 deletions
109
modules/backend/middlewares/access.go
Normal file
109
modules/backend/middlewares/access.go
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
// ctxKey — приватный тип для ключа контекста
|
||||
type ctxKey struct{}
|
||||
|
||||
// ginContextKey — уникальный ключ для хранения *gin.Context
|
||||
var ginContextKey = &ctxKey{}
|
||||
|
||||
// GinContextToContext сохраняет *gin.Context в context.Context запроса
|
||||
func GinContextToContext(c *gin.Context) {
|
||||
ctx := context.WithValue(c.Request.Context(), ginContextKey, c)
|
||||
c.Request = c.Request.WithContext(ctx)
|
||||
}
|
||||
|
||||
// GinContextFromContext извлекает *gin.Context из context.Context
|
||||
func GinContextFromContext(ctx context.Context) (*gin.Context, bool) {
|
||||
ginCtx, ok := ctx.Value(ginContextKey).(*gin.Context)
|
||||
return ginCtx, ok
|
||||
}
|
||||
|
||||
func JWTAuthMiddleware(secret string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 1. Получаем access_token из cookie
|
||||
tokenStr, err := c.Cookie("access_token")
|
||||
if err != nil {
|
||||
abortWithJSON(c, http.StatusUnauthorized, "missing access_token cookie")
|
||||
return
|
||||
}
|
||||
|
||||
// 2. Парсим токен с MapClaims
|
||||
token, err := jwt.Parse(tokenStr, func(t *jwt.Token) (interface{}, error) {
|
||||
if t.Method != jwt.SigningMethodHS256 {
|
||||
return nil, errors.New("unexpected signing method: " + t.Method.Alg())
|
||||
}
|
||||
return []byte(secret), nil // ← конвертируем string → []byte
|
||||
})
|
||||
if err != nil {
|
||||
abortWithJSON(c, http.StatusUnauthorized, "invalid token: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 3. Проверяем валидность
|
||||
if !token.Valid {
|
||||
abortWithJSON(c, http.StatusUnauthorized, "token is invalid")
|
||||
return
|
||||
}
|
||||
|
||||
// 4. Извлекаем user_id из claims
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
abortWithJSON(c, http.StatusUnauthorized, "invalid claims format")
|
||||
return
|
||||
}
|
||||
|
||||
userID, ok := claims["user_id"].(string)
|
||||
if !ok || userID == "" {
|
||||
abortWithJSON(c, http.StatusUnauthorized, "user_id claim missing or invalid")
|
||||
return
|
||||
}
|
||||
|
||||
// 5. Сохраняем в контексте
|
||||
c.Set("user_id", userID)
|
||||
|
||||
// 6. Для oapi-codegen — кладём gin.Context в request context
|
||||
GinContextToContext(c)
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// Вспомогательные функции (без изменений)
|
||||
func UserIDFromGin(c *gin.Context) (string, bool) {
|
||||
id, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
return "", false
|
||||
}
|
||||
if s, ok := id.(string); ok {
|
||||
return s, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func UserIDFromContext(ctx context.Context) (string, error) {
|
||||
ginCtx, ok := GinContextFromContext(ctx)
|
||||
if !ok {
|
||||
return "", errors.New("gin context not found")
|
||||
}
|
||||
userID, ok := UserIDFromGin(ginCtx)
|
||||
if !ok {
|
||||
return "", errors.New("user_id not found in context")
|
||||
}
|
||||
return userID, nil
|
||||
}
|
||||
|
||||
func abortWithJSON(c *gin.Context, code int, message string) {
|
||||
c.AbortWithStatusJSON(code, gin.H{
|
||||
"error": "unauthorized",
|
||||
"message": message,
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue