Добавлены недостающие файлы
This commit is contained in:
18
.env.example
18
.env.example
@@ -1,18 +0,0 @@
|
|||||||
# Database Configuration
|
|
||||||
DB_PASSWORD=postgres
|
|
||||||
DB_HOST=localhost
|
|
||||||
DB_PORT=5432
|
|
||||||
DB_USER=postgres
|
|
||||||
DB_NAME=authorization
|
|
||||||
|
|
||||||
# JWT Tokens (ВАЖНО: Сгенерируйте сложные случайные строки!)
|
|
||||||
# Можно использовать: openssl rand -base64 32
|
|
||||||
ACCESS_TOKEN_SECRET=kdfmklsdlmk;asdmkl;ds
|
|
||||||
REFRESH_TOKEN_SECRET=asdflmkasdfklmsdafklm
|
|
||||||
|
|
||||||
# Token TTL (optional, defaults from application.yaml)
|
|
||||||
# ACCESS_TOKEN_TTL_MINUTES=15
|
|
||||||
# REFRESH_TOKEN_TTL_MINUTES=90
|
|
||||||
|
|
||||||
# Server (optional)
|
|
||||||
# SERVER_PORT=8081
|
|
||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/golang-migrate/migrate/v4"
|
"github.com/golang-migrate/migrate/v4"
|
||||||
_ "github.com/golang-migrate/migrate/v4/database/postgres" // Импорт драйвера PostgreSQL
|
_ "github.com/golang-migrate/migrate/v4/database/postgres"
|
||||||
_ "github.com/golang-migrate/migrate/v4/source/file" // Импорт файлового драйвера
|
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ type Server struct {
|
|||||||
httpServer *http.Server
|
httpServer *http.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Run(port string,handler http.Handler) error {
|
func (s *Server) Run(port string, handler http.Handler) error {
|
||||||
s.httpServer = &http.Server{
|
s.httpServer = &http.Server{
|
||||||
Addr: ":" + port,
|
Addr: ":" + port,
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
ReadTimeout: 10 * time.Second,
|
ReadTimeout: 10 * time.Second,
|
||||||
WriteTimeout: 10 * time.Second,
|
WriteTimeout: 10 * time.Second,
|
||||||
MaxHeaderBytes: 1 << 20,
|
MaxHeaderBytes: 1 << 20,
|
||||||
@@ -21,7 +21,6 @@ func (s *Server) Run(port string,handler http.Handler) error {
|
|||||||
return s.httpServer.ListenAndServe()
|
return s.httpServer.ListenAndServe()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Shutdown(ctx context.Context) error{
|
func (s *Server) Shutdown(ctx context.Context) error {
|
||||||
return s.httpServer.Shutdown(ctx)
|
return s.httpServer.Shutdown(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type ServerConfig struct {
|
|||||||
|
|
||||||
type DatabaseConfig struct {
|
type DatabaseConfig struct {
|
||||||
Username string `yaml:"username" json:"username"`
|
Username string `yaml:"username" json:"username"`
|
||||||
Password string // Из переменной окружения, не из YAML
|
Password string
|
||||||
Host string `yaml:"host" json:"host"`
|
Host string `yaml:"host" json:"host"`
|
||||||
Port string `yaml:"port" json:"port"`
|
Port string `yaml:"port" json:"port"`
|
||||||
Sslmode string `yaml:"sslmode" json:"sslmode"`
|
Sslmode string `yaml:"sslmode" json:"sslmode"`
|
||||||
@@ -29,12 +29,12 @@ type DatabaseConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LoadConfig(absolutePath string) (*Config, error) {
|
func LoadConfig(absolutePath string) (*Config, error) {
|
||||||
// Загружаем .env файл (игнорируем ошибку, если файла нет)
|
|
||||||
_ = godotenv.Load()
|
_ = godotenv.Load()
|
||||||
|
|
||||||
config := &Config{}
|
config := &Config{}
|
||||||
|
|
||||||
// Читаем базовую конфигурацию из YAML (без секретов)
|
|
||||||
file, err := os.Open(absolutePath)
|
file, err := os.Open(absolutePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -56,28 +56,28 @@ func LoadConfig(absolutePath string) (*Config, error) {
|
|||||||
|
|
||||||
// loadFromEnv загружает секретные данные из переменных окружения
|
// loadFromEnv загружает секретные данные из переменных окружения
|
||||||
func loadFromEnv(config *Config) error {
|
func loadFromEnv(config *Config) error {
|
||||||
// Пароль БД (обязательный)
|
|
||||||
dbPassword := os.Getenv("DB_PASSWORD")
|
dbPassword := os.Getenv("DB_PASSWORD")
|
||||||
if dbPassword == "" {
|
if dbPassword == "" {
|
||||||
return fmt.Errorf("DB_PASSWORD environment variable is required")
|
return fmt.Errorf("DB_PASSWORD environment variable is required")
|
||||||
}
|
}
|
||||||
config.DB.Password = dbPassword
|
config.DB.Password = dbPassword
|
||||||
|
|
||||||
// Access Token Secret (обязательный)
|
|
||||||
accessTokenSecret := os.Getenv("ACCESS_TOKEN_SECRET")
|
accessTokenSecret := os.Getenv("ACCESS_TOKEN_SECRET")
|
||||||
if accessTokenSecret == "" {
|
if accessTokenSecret == "" {
|
||||||
return fmt.Errorf("ACCESS_TOKEN_SECRET environment variable is required")
|
return fmt.Errorf("ACCESS_TOKEN_SECRET environment variable is required")
|
||||||
}
|
}
|
||||||
config.Token.AccessToken.SecretWord = accessTokenSecret
|
config.Token.AccessToken.SecretWord = accessTokenSecret
|
||||||
|
|
||||||
// Refresh Token Secret (обязательный)
|
|
||||||
refreshTokenSecret := os.Getenv("REFRESH_TOKEN_SECRET")
|
refreshTokenSecret := os.Getenv("REFRESH_TOKEN_SECRET")
|
||||||
if refreshTokenSecret == "" {
|
if refreshTokenSecret == "" {
|
||||||
return fmt.Errorf("REFRESH_TOKEN_SECRET environment variable is required")
|
return fmt.Errorf("REFRESH_TOKEN_SECRET environment variable is required")
|
||||||
}
|
}
|
||||||
config.Token.RefreshToken.SecretWord = refreshTokenSecret
|
config.Token.RefreshToken.SecretWord = refreshTokenSecret
|
||||||
|
|
||||||
// Опциональные переопределения (если заданы в env)
|
|
||||||
if accessTTL := os.Getenv("ACCESS_TOKEN_TTL_MINUTES"); accessTTL != "" {
|
if accessTTL := os.Getenv("ACCESS_TOKEN_TTL_MINUTES"); accessTTL != "" {
|
||||||
ttl, err := strconv.Atoi(accessTTL)
|
ttl, err := strconv.Atoi(accessTTL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ func (h *Handler) userIdentity(c *gin.Context) {
|
|||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// requireRole - middleware-фабрика, возвращает middleware для проверки конкретных ролей
|
|
||||||
func (h *Handler) requireRole(allowedRoles ...internal.UserRole) gin.HandlerFunc {
|
func (h *Handler) requireRole(allowedRoles ...internal.UserRole) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
userRole, exists := c.Get(userRoleKey)
|
userRole, exists := c.Get(userRoleKey)
|
||||||
@@ -86,31 +85,4 @@ func (h *Handler) requireTeacher() gin.HandlerFunc {
|
|||||||
|
|
||||||
func (h *Handler) requireStudent() gin.HandlerFunc {
|
func (h *Handler) requireStudent() gin.HandlerFunc {
|
||||||
return h.requireRole(internal.Student, internal.Teacher, internal.Admin)
|
return h.requireRole(internal.Student, internal.Teacher, internal.Admin)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) checkAdminIdentity(c *gin.Context) {
|
|
||||||
header := c.GetHeader(authorizationHeader)
|
|
||||||
if header == "" {
|
|
||||||
newErrorResponse(c, http.StatusUnauthorized, "Пустой header авторизации")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
headerParts := strings.Split(header, " ")
|
|
||||||
if len(headerParts) != 2 {
|
|
||||||
newErrorResponse(c, http.StatusUnauthorized, "Невалидный токен JWT")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
userRole, err := h.services.ParseToken(headerParts[1])
|
|
||||||
|
|
||||||
if userRole != string(internal.Admin) {
|
|
||||||
newErrorResponse(c, http.StatusUnauthorized, "Недостаточно прав для выполнения запроса")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
newErrorResponse(c, http.StatusUnauthorized, "Ошибка при извлечении claims")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Set(userRoleKey, userRole)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user