Shiro的验证机制 和同一浏览器 多次登录的BUG

来源:互联网 发布:python语言 编辑:程序博客网 时间:2024/06/14 06:33

Shiro同时登陆多个账户异常

关于一个浏览器同时登陆多个账户,自动跳转到原登录页面的逻辑错误。
方法1

对shiro源码进行了调试,发现是AuthenticationFilter验证逻辑的问题:
1.它首先验证是否有允许访问页面(isAccessAllowed方法)。
2.在拒绝访问中(FormAuthenticationFilter的onAccessDenied方法)才会进行判断是否是登录提交(isLoginSubmission)。

因为已经登陆了一个用户所以isAccessAllowed直接返回为true,进入LoginController,找到匹配方法fail直接返回LOGIN_PAGE。
由于有权限访问该登录(其他)页面FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME没有值,返回为Null,所以在
keta-security中会跳转到login页面并且显示"登陆失败,其他错误!"。

分析、修改逻辑,首先验证是否是登录操作,再进行验证是否有权限访问页面。继承FormAuthenticationFilter,覆盖isAccessAllowed方法。

view source
print?
01/**
02 
03 * @author  <a href="mailto:ketayao@gmail.com">ketayao</a>
04 * Version  1.1.0
05 * @since   2012-10-29 上午9:37:02
06 */
07  
08public class BaseFormAuthenticationFilter extends FormAuthenticationFilter {
09    private static final Logger log = LoggerFactory.getLogger(BaseFormAuthenticationFilter.class);
10      
11    /**
12     *
13     * @param request
14     * @param response
15     * @param mappedValue
16     * @return 
17     * @see org.apache.shiro.web.filter.authc.AuthenticatingFilter#isAccessAllowed(javax.servlet.ServletRequest, javax.servlet.ServletResponse, java.lang.Object)
18     */
19    @Override
20    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
21        try {
22            // 先判断是否是登录操作
23            if (isLoginSubmission(request, response)) {
24                if (log.isTraceEnabled()) {
25                    log.trace("Login submission detected.  Attempting to execute login.");
26                }
27                return false;
28            }
29        catch (Exception e) {
30            log.error(Exceptions.getStackTraceAsString(e));
31        }
32  
33        return super.isAccessAllowed(request, response, mappedValue);
34    }
35}

方法2

  • 在loginUrl页面判断用户是否已经登陆,如果已经登陆了,则提示用户可以选择进入系统或者登出:
<ui:fragment rendered="#{not empty request.remoteUser}">      您已经登陆系统,请选择<a href="dashboard.html">进入系统</>,或者<a href="logout.do">登出系统来用其它用户登陆</></ui:fragment>
  • 方法3
  • 或者,你希望用户这样干的时候,直接将其重定向到系统首页去,则利用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.}