@@ -54,142 +54,135 @@ func SetupAdminRoutes(
5454
5555 }
5656
57+ // 将管理后台静态资源与前端入口注册为公开路由,允许未认证用户加载登录页面和相关静态资源
58+ // 注意:API 路由仍然放在受保护的 authGroup 中
59+ themeDir := "./" + cfg .ThemesSelect
60+
61+ // css
62+ adminGroup .GET ("/css/*filepath" , func (c * gin.Context ) {
63+ fp := c .Param ("filepath" )
64+ p := filepath .Join (themeDir , "admin" , "css" , fp )
65+ if _ , err := os .Stat (p ); err != nil {
66+ c .Status (404 )
67+ return
68+ }
69+ c .File (p )
70+ })
71+
72+ // HEAD for css
73+ adminGroup .HEAD ("/css/*filepath" , func (c * gin.Context ) {
74+ fp := c .Param ("filepath" )
75+ p := filepath .Join (themeDir , "admin" , "css" , fp )
76+ if _ , err := os .Stat (p ); err != nil {
77+ c .Status (404 )
78+ return
79+ }
80+ c .File (p )
81+ })
82+
83+ // js
84+ adminGroup .GET ("/js/*filepath" , func (c * gin.Context ) {
85+ fp := c .Param ("filepath" )
86+ p := filepath .Join (themeDir , "admin" , "js" , fp )
87+ if _ , err := os .Stat (p ); err != nil {
88+ c .Status (404 )
89+ return
90+ }
91+ c .File (p )
92+ })
93+
94+ // HEAD for js
95+ adminGroup .HEAD ("/js/*filepath" , func (c * gin.Context ) {
96+ fp := c .Param ("filepath" )
97+ p := filepath .Join (themeDir , "admin" , "js" , fp )
98+ if _ , err := os .Stat (p ); err != nil {
99+ c .Status (404 )
100+ return
101+ }
102+ c .File (p )
103+ })
104+
105+ // templates
106+ adminGroup .GET ("/templates/*filepath" , func (c * gin.Context ) {
107+ fp := c .Param ("filepath" )
108+ p := filepath .Join (themeDir , "admin" , "templates" , fp )
109+ if _ , err := os .Stat (p ); err != nil {
110+ c .Status (404 )
111+ return
112+ }
113+ c .File (p )
114+ })
115+
116+ // HEAD for templates
117+ adminGroup .HEAD ("/templates/*filepath" , func (c * gin.Context ) {
118+ fp := c .Param ("filepath" )
119+ p := filepath .Join (themeDir , "admin" , "templates" , fp )
120+ if _ , err := os .Stat (p ); err != nil {
121+ c .Status (404 )
122+ return
123+ }
124+ c .File (p )
125+ })
126+
127+ // assets and components
128+ adminGroup .GET ("/assets/*filepath" , func (c * gin.Context ) {
129+ fp := c .Param ("filepath" )
130+ p := filepath .Join (themeDir , "assets" , fp )
131+ if _ , err := os .Stat (p ); err != nil {
132+ c .Status (404 )
133+ return
134+ }
135+ c .File (p )
136+ })
137+
138+ // HEAD for assets
139+ adminGroup .HEAD ("/assets/*filepath" , func (c * gin.Context ) {
140+ fp := c .Param ("filepath" )
141+ p := filepath .Join (themeDir , "assets" , fp )
142+ if _ , err := os .Stat (p ); err != nil {
143+ c .Status (404 )
144+ return
145+ }
146+ c .File (p )
147+ })
148+
149+ adminGroup .GET ("/components/*filepath" , func (c * gin.Context ) {
150+ fp := c .Param ("filepath" )
151+ p := filepath .Join (themeDir , "components" , fp )
152+ if _ , err := os .Stat (p ); err != nil {
153+ c .Status (404 )
154+ return
155+ }
156+ c .File (p )
157+ })
158+
159+ // HEAD for components
160+ adminGroup .HEAD ("/components/*filepath" , func (c * gin.Context ) {
161+ fp := c .Param ("filepath" )
162+ p := filepath .Join (themeDir , "components" , fp )
163+ if _ , err := os .Stat (p ); err != nil {
164+ c .Status (404 )
165+ return
166+ }
167+ c .File (p )
168+ })
169+
170+ // 管理前端入口公开:允许未认证用户加载登录页面
171+ adminGroup .GET ("/" , func (c * gin.Context ) {
172+ static .ServeAdminPage (c , cfg )
173+ })
174+ // HEAD for admin entry
175+ adminGroup .HEAD ("/" , func (c * gin.Context ) {
176+ static .ServeAdminPage (c , cfg )
177+ })
178+
57179 // 使用复用的中间件实现(JWT 用户认证并要求 admin 角色)
58180 combinedAuthMiddleware := middleware .CombinedAdminAuth (cfg , userService )
59181
60182 // 需要管理员认证的API路由组
61183 authGroup := adminGroup .Group ("" )
62184 authGroup .Use (combinedAuthMiddleware )
63185 {
64- // 显式为管理后台静态资源注册受保护的 GET 处理器,确保这些静态文件也需要管理员认证
65- themeDir := "./" + cfg .ThemesSelect
66-
67- // css
68- authGroup .GET ("/css/*filepath" , func (c * gin.Context ) {
69- fp := c .Param ("filepath" )
70- p := filepath .Join (themeDir , "admin" , "css" , fp )
71- if _ , err := os .Stat (p ); err != nil {
72- c .Status (404 )
73- return
74- }
75- c .File (p )
76- })
77-
78- // HEAD for css (ensure middleware runs for HEAD as well)
79- authGroup .HEAD ("/css/*filepath" , func (c * gin.Context ) {
80- fp := c .Param ("filepath" )
81- p := filepath .Join (themeDir , "admin" , "css" , fp )
82- if _ , err := os .Stat (p ); err != nil {
83- c .Status (404 )
84- return
85- }
86- c .File (p )
87- })
88-
89- // js
90- authGroup .GET ("/js/*filepath" , func (c * gin.Context ) {
91- fp := c .Param ("filepath" )
92- p := filepath .Join (themeDir , "admin" , "js" , fp )
93- if _ , err := os .Stat (p ); err != nil {
94- c .Status (404 )
95- return
96- }
97- c .File (p )
98- })
99-
100- // HEAD for js
101- authGroup .HEAD ("/js/*filepath" , func (c * gin.Context ) {
102- fp := c .Param ("filepath" )
103- p := filepath .Join (themeDir , "admin" , "js" , fp )
104- if _ , err := os .Stat (p ); err != nil {
105- c .Status (404 )
106- return
107- }
108- c .File (p )
109- })
110-
111- // templates
112- authGroup .GET ("/templates/*filepath" , func (c * gin.Context ) {
113- fp := c .Param ("filepath" )
114- p := filepath .Join (themeDir , "admin" , "templates" , fp )
115- if _ , err := os .Stat (p ); err != nil {
116- c .Status (404 )
117- return
118- }
119- c .File (p )
120- })
121-
122- // HEAD for templates
123- authGroup .HEAD ("/templates/*filepath" , func (c * gin.Context ) {
124- fp := c .Param ("filepath" )
125- p := filepath .Join (themeDir , "admin" , "templates" , fp )
126- if _ , err := os .Stat (p ); err != nil {
127- c .Status (404 )
128- return
129- }
130- c .File (p )
131- })
132-
133- // assets and components
134- authGroup .GET ("/assets/*filepath" , func (c * gin.Context ) {
135- fp := c .Param ("filepath" )
136- p := filepath .Join (themeDir , "assets" , fp )
137- if _ , err := os .Stat (p ); err != nil {
138- c .Status (404 )
139- return
140- }
141- c .File (p )
142- })
143-
144- // HEAD for assets
145- authGroup .HEAD ("/assets/*filepath" , func (c * gin.Context ) {
146- fp := c .Param ("filepath" )
147- p := filepath .Join (themeDir , "assets" , fp )
148- if _ , err := os .Stat (p ); err != nil {
149- c .Status (404 )
150- return
151- }
152- c .File (p )
153- })
154- authGroup .GET ("/components/*filepath" , func (c * gin.Context ) {
155- fp := c .Param ("filepath" )
156- p := filepath .Join (themeDir , "components" , fp )
157- if _ , err := os .Stat (p ); err != nil {
158- c .Status (404 )
159- return
160- }
161- c .File (p )
162- })
163-
164- // HEAD for components
165- authGroup .HEAD ("/components/*filepath" , func (c * gin.Context ) {
166- fp := c .Param ("filepath" )
167- p := filepath .Join (themeDir , "components" , fp )
168- if _ , err := os .Stat (p ); err != nil {
169- c .Status (404 )
170- return
171- }
172- c .File (p )
173- })
174- authGroup .GET ("/components/*filepath" , func (c * gin.Context ) {
175- fp := c .Param ("filepath" )
176- p := filepath .Join (themeDir , "components" , fp )
177- if _ , err := os .Stat (p ); err != nil {
178- c .Status (404 )
179- return
180- }
181- c .File (p )
182- })
183-
184- // 管理前端入口受保护:仅管理员可访问 /admin/
185- authGroup .GET ("/" , func (c * gin.Context ) {
186- static .ServeAdminPage (c , cfg )
187- })
188- // HEAD for admin entry
189- authGroup .HEAD ("/" , func (c * gin.Context ) {
190- static .ServeAdminPage (c , cfg )
191- })
192-
193186 // 仪表板和统计
194187 authGroup .GET ("/dashboard" , adminHandler .Dashboard )
195188 authGroup .GET ("/stats" , adminHandler .GetStats )
0 commit comments