shiro认证成功后,没有跳转到配置的successUrl

项目框架:spring boot + jpa,maven管理

昨天在项目中使用shiro的时候,发现shiro认证成功后一直跳转的界面是"/"这个界面,报一个404异常,自己配置的successUrl感觉没有起作用,总结前人博客,并且查看源码,知道了原因:

首先,shiro在认证成功后,会调用onLoginSuccess方法,

onLoginSuccess(token, subject, request, response);

追踪这个方法

protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,
                                     ServletRequest request, ServletResponse response) throws Exception {
        issueSuccessRedirect(request, response);
        //we handled the success redirect directly, prevent the chain from continuing:
        return false;
    }

发现内部调用了issueSuccessRedirect(request,response)方法,继续追踪

protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception {
        WebUtils.redirectToSavedRequest(request, response, getSuccessUrl());
    }

发现它内部又调用了WebUtils工具类的redirectToSavedRequest()方法,继续追踪

public static void redirectToSavedRequest(ServletRequest request, ServletResponse response, String fallbackUrl)
            throws IOException {
        String successUrl = null;
        boolean contextRelative = true;
        SavedRequest savedRequest = WebUtils.getAndClearSavedRequest(request);
        if (savedRequest != null && savedRequest.getMethod().equalsIgnoreCase(AccessControlFilter.GET_METHOD)) {
            successUrl = savedRequest.getRequestUrl();
            contextRelative = false;
        }

        if (successUrl == null) {
            successUrl = fallbackUrl;
        }

        if (successUrl == null) {
            throw new IllegalStateException("Success URL not available via saved request or via the " +
                    "successUrlFallback method parameter. One of these must be non-null for " +
                    "issueSuccessRedirect() to work.");
        }

        WebUtils.issueRedirect(request, response, successUrl, null, contextRelative);
    }

}

在这个方法里面终于找到了与successUrl相关的内容,分析逻辑关系,我们可以知道,在第一个if语句中,如果savedRequest不会null,则会覆盖掉我们设置的successUrl,所以,我们自己配置的successUrl只有在SavedRequest对象为null的时候,才会生效。

最后,我们需要了解这个savedRequest对象是怎么来的,继续追踪,进入WebUtils.getAndClearSavedRequest(request)方法

public static final String SAVED_REQUEST_KEY = "shiroSavedRequest";

public static SavedRequest getAndClearSavedRequest(ServletRequest request) {
        SavedRequest savedRequest = getSavedRequest(request);
        if (savedRequest != null) {
            Subject subject = SecurityUtils.getSubject();
            Session session = subject.getSession();
            session.removeAttribute(SAVED_REQUEST_KEY);
        }
        return savedRequest;
    }

    public static SavedRequest getSavedRequest(ServletRequest request) {
        SavedRequest savedRequest = null;
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession(false);
        if (session != null) {
            savedRequest = (SavedRequest) session.getAttribute(SAVED_REQUEST_KEY);
        }
        return savedRequest;
    }

从上段源码我们可以看出来,savedRequest对象是绑定在session中的,并且它的key值为shiroSavedRequest。

到这里,我们基本清楚了我们设置的successUrl为什么没有生效了。

解决方案:

需要在我们自己的继承了FormAuthenticationFilter的类中重写onloginSuccess()方法。

/**
	 * 因为发现设置的successUrl没生效,所以追踪源码发现如果SavedRequest对象不为null,则它会覆盖掉我们设置
	 * 的successUrl,所以我们要重写onLoginSuccess方法,在它覆盖掉我们设置的successUrl之前,去除掉
	 * SavedRequest对象,SavedRequest对象的获取方式为:
	 * savedRequest = (SavedRequest) session.getAttribute(SAVED_REQUEST_KEY);
	 * public static final String SAVED_REQUEST_KEY = "shiroSavedRequest";
	 * 解决方案:从session对象中移出shiroSavedRequest
	 */
	@Override
	protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
			ServletResponse response) throws Exception {
		if (!StringUtils.isEmpty(getSuccessUrl())) {
			// getSession(false):如果当前session为null,则返回null,而不是创建一个新的session
			Session session = subject.getSession(false);
			if (session != null) {
				session.removeAttribute("shiroSavedRequest");
			}
		}
		return super.onLoginSuccess(token, subject, request, response);
	}

 

你可能感兴趣的:(Shiro)