chore: implement config management and HTTP transport layer with CORS support
This commit is contained in:
parent
9df4673657
commit
74528f2d86
@ -104,7 +104,9 @@ func (l *ViperConfigLoader) loadEnvFile(v *viper.Viper) error {
|
||||
|
||||
// Lưu giá trị gốc cho tương thích ngược
|
||||
v.Set(key, val)
|
||||
os.Setenv(key, val)
|
||||
if err := os.Setenv(key, val); err != nil {
|
||||
return fmt.Errorf("failed to set environment variable %s: %w", key, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@ -34,8 +34,6 @@ type DatabaseConfig struct {
|
||||
MigrationPath string `mapstructure:"migration_path" validate:"required"`
|
||||
}
|
||||
|
||||
<<<<<<< Updated upstream
|
||||
=======
|
||||
// JWTConfig chứa cấu hình cho JWT
|
||||
type JWTConfig struct {
|
||||
Secret string `mapstructure:"secret" validate:"required,min=32"`
|
||||
@ -46,7 +44,7 @@ type JWTConfig struct {
|
||||
Audience []string `mapstructure:"audience" validate:"required,min=1"`
|
||||
}
|
||||
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
// Config là struct tổng thể chứa tất cả các cấu hình
|
||||
type Config struct {
|
||||
App AppConfig `mapstructure:"app" validate:"required"`
|
||||
|
||||
88
internal/transport/http/middleware/cors.go
Normal file
88
internal/transport/http/middleware/cors.go
Normal file
@ -0,0 +1,88 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// CORSConfig chứa cấu hình cho CORS
|
||||
type CORSConfig struct {
|
||||
AllowOrigins []string `yaml:"allow_origins"`
|
||||
AllowMethods []string `yaml:"allow_methods"`
|
||||
AllowHeaders []string `yaml:"allow_headers"`
|
||||
ExposeHeaders []string `yaml:"expose_headers"`
|
||||
AllowCredentials bool `yaml:"allow_credentials"`
|
||||
MaxAge int `yaml:"max_age"`
|
||||
}
|
||||
|
||||
// DefaultCORSConfig trả về cấu hình CORS mặc định
|
||||
func DefaultCORSConfig() CORSConfig {
|
||||
return CORSConfig{
|
||||
AllowOrigins: []string{"*"},
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"},
|
||||
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization"},
|
||||
ExposeHeaders: []string{"Content-Length"},
|
||||
AllowCredentials: true,
|
||||
MaxAge: 12 * 60 * 60, // 12 hours
|
||||
}
|
||||
}
|
||||
|
||||
// CORS trả về middleware xử lý CORS
|
||||
func CORS(config CORSConfig) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// Set CORS headers
|
||||
origin := c.GetHeader("Origin")
|
||||
if len(config.AllowOrigins) == 0 {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
} else {
|
||||
for _, o := range config.AllowOrigins {
|
||||
if o == "*" || o == origin {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if config.AllowCredentials {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
}
|
||||
|
||||
if len(config.ExposeHeaders) > 0 {
|
||||
c.Writer.Header().Set("Access-Control-Expose-Headers", joinStrings(config.ExposeHeaders, ", "))
|
||||
}
|
||||
|
||||
// Handle preflight requests
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
if len(config.AllowMethods) > 0 {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", joinStrings(config.AllowMethods, ", "))
|
||||
}
|
||||
|
||||
if len(config.AllowHeaders) > 0 {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", joinStrings(config.AllowHeaders, ", "))
|
||||
}
|
||||
|
||||
if config.MaxAge > 0 {
|
||||
c.Writer.Header().Set("Access-Control-Max-Age", string(rune(config.MaxAge)))
|
||||
}
|
||||
|
||||
c.AbortWithStatus(204)
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// Hàm hỗ trợ nối các chuỗi
|
||||
func joinStrings(strs []string, sep string) string {
|
||||
if len(strs) == 0 {
|
||||
return ""
|
||||
}
|
||||
if len(strs) == 1 {
|
||||
return strs[0]
|
||||
}
|
||||
result := strs[0]
|
||||
for _, s := range strs[1:] {
|
||||
result += sep + s
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -19,7 +19,7 @@ func TestSecurityMiddlewares(t *testing.T) {
|
||||
config := middleware.DefaultSecurityConfig()
|
||||
|
||||
// Tùy chỉnh cấu hình nếu cần
|
||||
config.CORS.AllowedOrigins = []string{"https://example.com"}
|
||||
config.CORS.AllowOrigins = []string{"https://example.com"}
|
||||
config.RateLimit.Rate = 100 // 100 requests per minute
|
||||
config.Headers.ContentSecurityPolicy = "default-src 'self'; script-src 'self'"
|
||||
|
||||
@ -39,7 +39,10 @@ func TestSecurityMiddlewares(t *testing.T) {
|
||||
t.Run("Test CORS", func(t *testing.T) {
|
||||
resp, err := http.Get(ts.URL + "/test")
|
||||
assert.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
defer func() {
|
||||
err := resp.Body.Close()
|
||||
assert.NoError(t, err, "failed to close response body")
|
||||
}()
|
||||
|
||||
// Kiểm tra CORS header
|
||||
assert.Equal(t, "https://example.com", resp.Header.Get("Access-Control-Allow-Origin"))
|
||||
@ -51,7 +54,8 @@ func TestSecurityMiddlewares(t *testing.T) {
|
||||
for i := 0; i < 110; i++ {
|
||||
resp, err := http.Get(ts.URL + "/test")
|
||||
assert.NoError(t, err)
|
||||
resp.Body.Close()
|
||||
err = resp.Body.Close()
|
||||
assert.NoError(t, err, "failed to close response body")
|
||||
|
||||
if i >= 100 {
|
||||
// Sau 100 request, server sẽ trả về 429
|
||||
@ -67,7 +71,10 @@ func TestSecurityMiddlewares(t *testing.T) {
|
||||
t.Run("Test Security Headers", func(t *testing.T) {
|
||||
resp, err := http.Get(ts.URL + "/test")
|
||||
assert.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
defer func() {
|
||||
err := resp.Body.Close()
|
||||
assert.NoError(t, err, "failed to close response body")
|
||||
}()
|
||||
|
||||
// Kiểm tra các security headers
|
||||
headers := []string{
|
||||
|
||||
@ -22,30 +22,9 @@ func SetupRouter(cfg *config.Config) *gin.Engine {
|
||||
// Recovery middleware
|
||||
router.Use(gin.Recovery())
|
||||
|
||||
<<<<<<< Updated upstream
|
||||
// CORS middleware nếu cần
|
||||
// router.Use(middleware.CORS())
|
||||
=======
|
||||
// CORS middleware
|
||||
router.Use(middleware.CORS(middleware.DefaultCORSConfig()))
|
||||
|
||||
// Khởi tạo repositories
|
||||
userRepo := persistence.NewUserRepository(db)
|
||||
roleRepo := persistence.NewRoleRepository(db)
|
||||
|
||||
// Khởi tạo services
|
||||
authSvc := service.NewAuthService(
|
||||
userRepo,
|
||||
roleRepo,
|
||||
cfg.JWT.Secret,
|
||||
time.Duration(cfg.JWT.AccessTokenExpire)*time.Minute,
|
||||
cfg.JWT.RefreshTokenExpire * 24, // Convert days to hours
|
||||
)
|
||||
|
||||
// Khởi tạo middleware
|
||||
authMiddleware := middleware.NewAuthMiddleware(authSvc)
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
// Khởi tạo các handlers
|
||||
healthHandler := handler.NewHealthHandler(cfg)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user