package router import ( "time" "github.com/freefire/jiang13-bbs/config" "github.com/freefire/jiang13-bbs/handler" "github.com/freefire/jiang13-bbs/middleware" "github.com/freefire/jiang13-bbs/model" "github.com/freefire/jiang13-bbs/service" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" ) // Setup 初始化路由 func Setup(cfg *config.Config) (*gin.Engine, error) { if cfg.DevMode { gin.SetMode(gin.DebugMode) } else { gin.SetMode(gin.ReleaseMode) } r := gin.New() r.Use(gin.Recovery()) r.Use(gin.Logger()) // 全局安全响应头 r.Use(middleware.SecurityHeaders()) // CORS r.Use(cors.New(cors.Config{ AllowOrigins: []string{"http://localhost:3000", "http://127.0.0.1:3000"}, AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "X-CSRF-Token"}, AllowCredentials: true, MaxAge: 12 * time.Hour, })) // 服务 authSvc := service.NewAuthService(model.DB, cfg.JWTSecret) boardSvc := service.NewBoardService(model.DB) postSvc := service.NewPostService(model.DB) commentSvc := service.NewCommentService(model.DB) likeSvc := service.NewLikeService(model.DB) notifSvc := service.NewNotificationService(model.DB) limiter := service.DefaultRateLimiter() h := &handler.Handlers{ Cfg: cfg, Auth: authSvc, Board: boardSvc, Post: postSvc, Comment: commentSvc, Like: likeSvc, Notification: notifSvc, } authMW := middleware.NewAuthMiddleware(authSvc) // 健康检查 & SEO r.GET("/health", h.Health) r.GET("/robots.txt", h.RobotsTxt) r.GET("/sitemap.xml", h.SitemapXML) // 公开 API(可选登录) pubAPI := r.Group("/api", authMW.OptionalAuth()) { pubAPI.GET("/me", h.Me) pubAPI.GET("/boards", h.Boards) pubAPI.GET("/posts", h.Posts) pubAPI.GET("/posts/:id", h.PostDetail) pubAPI.GET("/posts/:id/comments", h.PostComments) pubAPI.GET("/users/:id", h.UserProfile) pubAPI.GET("/users/:id/comments", h.UserComments) pubAPI.POST("/register", middleware.RateLimitMiddleware(limiter, service.RateRegister), h.Register) pubAPI.POST("/login", middleware.RateLimitMiddleware(limiter, service.RateLogin), h.Login) // refresh token 端点:access 过期后用 refresh 换新 token(需 CSRF 防护) pubAPI.POST("/auth/refresh", middleware.CSRFMiddleware(), h.Refresh) } // 需登录 API(先鉴权,再 CSRF 防护) api := r.Group("/api", authMW.RequireAuth(), middleware.CSRFMiddleware()) { api.POST("/logout", h.Logout) api.POST("/change-password", h.ChangePassword) api.POST("/posts", middleware.RateLimitMiddleware(limiter, service.RatePost), h.CreatePost) api.PUT("/posts/:id", h.UpdatePost) api.DELETE("/posts/:id", h.DeletePost) api.PUT("/posts/:id/pin", h.TogglePin) api.PUT("/posts/:id/recommend", h.ToggleRecommend) api.POST("/posts/:id/like", h.ToggleLike) api.POST("/posts/:id/comments", middleware.RateLimitMiddleware(limiter, service.RateComment), h.CreateComment) api.DELETE("/posts/:id/comments/:cid", h.DeleteComment) // 通知 api.GET("/notifications", h.Notifications) api.GET("/notifications/unread-count", h.UnreadCount) api.PUT("/notifications/:id/read", h.MarkRead) api.PUT("/notifications/read-all", h.MarkAllRead) } // 管理员 API(同样需要 CSRF 防护) adminAPI := r.Group("/api/admin", authMW.RequireAuth(), middleware.CSRFMiddleware(), authMW.RequireAdmin()) { adminAPI.GET("/dashboard", func(c *gin.Context) { c.JSON(200, gin.H{"message": "admin dashboard"}) }) } r.NoRoute(func(c *gin.Context) { c.JSON(404, gin.H{"error": "not found"}) }) return r, nil }