做的事情越多,越能体会到德胜大大的那句话:
天下的事,并不以你的意志为转移
你想这样,偏一下子办不到
等转一圈回来,事情恰又办成了
一、问题描述
输入密码正确,登录表单提交后,页面停留在当前页,没有自动跳转到后台仪表盘。
二、排查思路
①CTRL+F5强制刷新浏览器,检查是否为浏览器缓存导致的问题
②查看goland终端,检查是否有路由错误或者其他的报错
③如果路由没有错,那就需要查看跳转路由是否被认证中间件拦截,F12打开浏览器开发者工具,切到 Network 标签,然后再次点击登录按钮,看到 HTTP 302 响应,Location 还是 /admin/login,并且请求被反复重定向,说明中间件拦截了登录页。
三、根本原因
此前我并没有遇到这类问题,于是把相关的代码上传给AI,得知根本原因为:路由分组不当,登录/登出等公开路由与需要认证的路由放在同一个路由组内,并全局使用了认证中间件,导致登录页面本身就被拦截,无法正常访问或提交。
什么是重定向?
当浏览器发起一个请求(比如 GET /login),服务器没有直接返回内容,而是返回一个 3xx 状态码(通常是 302 或 301)和一个 Location 头,指向新的 URL。浏览器收到这个响应后,会自动向新 URL 发起请求,这个过程就是重定向。
全局认证中间件的效果是什么?
中间件的逻辑是:“未登录就重定向到登录页”。那么当用户 第一次访问登录页时,请求会先经过中间件。中间件检查登录状态 → 发现未登录 → 执行 “重定向跳转到登录页” → 又跳到登录页本身 → 再次触发中间件 → 无限重定向循环。
登录是用来获取认证凭证的入口,它天然就不需要先检查登录状态,否则就陷入了“没有钥匙就不能进门,但钥匙在门里面”的死循环,所以登录页必须脱离认证中间件
中间件的拦截逻辑?
①尝试从请求中获取凭据(比如 Cookie)。
②如果找到了 Cookie 并且 Cookie 有效,放行(c.Next())。
③如果没找到 Cookie 或 Cookie 已失效,则拦截并重定向。
四、解决办法
正确的做法是:登录/登出放在公开路由组(没有认证中间件),需要登录才能访问的页面放在私有路由组(有认证中间件)。
大致的代码逻辑:
// 公开路由(无需认证)
adminPublic := engine.Group(adminPath)
{
adminPublic.GET("/login", authHandler.LoginPage)
adminPublic.POST("/login", authHandler.Login)
adminPublic.GET("/logout", authHandler.Logout)
}
// 私有路由(需要认证)
adminPrivate := engine.Group(adminPath)
adminPrivate.Use(authHandler.AuthRequired())
{
adminPrivate.GET("/", dashboardHandler)
adminPrivate.GET("/posts", postHandler)
// ...
}
什么是Gin路由组?
Gin 中,可以用 engine.Group(path) 创建一个路由组,然后为该组里的所有路由统一添加中间件。
例如:
adminGroup := engine.Group("/admin")
adminGroup.Use(AuthMiddleware) // 这个组里所有路由都会经过 AuthMiddleware
adminGroup.GET("/dashboard", dashboardHandler)
adminGroup.GET("/posts", postHandler)
此时 /admin/dashboard 和 /admin/posts 都会先执行 AuthMiddleware。
如果把登录、登出也放在同一个组里:
adminGroup.GET("/login", loginPageHandler)
adminGroup.POST("/login", loginHandler)
adminGroup.GET("/logout", logoutHandler)
那么这些登录、登出路由也会被 AuthMiddleware 拦截,导致无法跳转。
暂无评论,快来抢沙发吧!