做的事情越多,越能体会到德胜大大的那句话:

天下的事,并不以你的意志为转移

你想这样,偏一下子办不到

等转一圈回来,事情恰又办成了

一、问题描述

输入密码正确,登录表单提交后,页面停留在当前页,没有自动跳转到后台仪表盘。

二、排查思路

①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 拦截,导致无法跳转。

评论 (0)

发表评论

头像预览
QQ 邮箱会自动使用 QQ 头像,其他邮箱使用默认企鹅头像。

暂无评论,快来抢沙发吧!