Shiro中,对已登陆用户再次访问loginUrl的控制

最近在做一个项目,第一次使用Shiro,配置倒是非常简单,测试时有用户抱怨说反复登陆,都停留在登陆界面。于是分析其行为,最终发现,用户很可能是收藏了登陆界面,在已经登陆到系统的前提下,用户没有退出,直接用收藏夹切换到登陆界面,打算用另外一个用户登陆。通过阅读文档,可以知道Shiro对于用户行为有三种方式过滤:

  • 如果用户没有登陆,直接来到了登陆页面,则成功登陆后,用户会被重定向到successUrl界面。
  • 如果用户没有登陆,直接访问了未授权页面,则会被重定向到loginUrl页面(即登陆页面),登陆成功后,会被重新定向到之前用户直接访问的页面。
  • 用户已经登陆,则可以直接访问权限内的页面

那么,问题就出在,用户已经登陆的情况下,用户直接访问了loginUrl,这时候,Shiro不会将其重定向,而Shiro的用户登陆逻辑,又是向loginUrl发送一个POST请求。因此,就出现了似乎是死循环的逻辑。

放狗搜索,最终在stackoverflow得到了一些答案,总结一下,基本上两种结局方案

  • 在loginUrl页面判断用户是否已经登陆,如果已经登陆了,则提示用户可以选择进入系统或者登出:
<ui:fragment rendered="#{not empty request.remoteUser}">
    您已经登陆系统,请选择<a href="dashboard.html">进入系统</>,或者<a href="logout.do">登出系统来用其它用户登陆</>
</ui:fragment>
  • 或者,你希望用户这样干的时候,直接将其重定向到系统首页去,则利用filter来做此事
@WebFilter(urlPatterns = "/login.xhtml")
public class LoginPageFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        if (request.getRemoteUser() != null)) {
            response.sendRedirect(request.getContextPath() + "/home.xhtml"); // Redirect to home page.
        } else {
            chain.doFilter(req, res); // User is not logged-in, so just continue request.
        }
    }

    // Add/generate init() and destroy() with NOOP.
}

至于Shiro为什么不做控制,或者预留一个选项来做控制,就不得而知了。

Show Comments