Shiro session过期跳转到登录页面问题
shrio的session过期后(工程重启或者用户长时间没进行任何操作),当客户端再次向服务端发起请求时,shrio会判断用户没有登录授权,然后对请求做一个重定向(重定向到登录页面)。上面的过程是对浏览器地址栏的请求或者form表单的请求生效,如果是ajax请求则不会重定向成功。因为ajax请求只做局部刷新,不会重新加载整个页面,所以ajax不支持重定向。
问题定位:
shiro中登录验证不通过会被拦截,然后会走FormAuthenticationFilter过滤器的onAccessDenied方法(这个可以通过在onAccessDenied方法中打断点验证)。然后跟踪onAccessDenied方法,发现
最后都会将请求重定向到登录页(登录页的具体路径来自于shiro中的配置:ShiroFilterFactoryBean.setLoginUrl方法)。所以问题就出在默认的重定向方法,我们需要对重定向方法进行改动
解决方法:
1>服务端:
1、查看FormAuthenticationFilter类,对里面的重定向方法onAccessDenied进行跟踪
FormAuthenticationFilter类:
ORD_PARAM;
private String rememberMeParam = DEFAULT_REMEMBER_ME_PARAM;
private String failureKeyAttribute = DEFAULT_ERROR_KEY_ATTRIBUTE_NAME;
public FormAuthenticationFilter() {
setLoginUrl(DEFAULT_LOGIN_URL);
}
@Override
public void setLoginUrl(String loginUrl) {
String previous = getLoginUrl();
if (previous != null) {
this.appliedPaths.remove(previous);
}
super.setLoginUrl(loginUrl);
if (log.isTraceEnabled()) {
log.trace("Adding login url to applied paths.");
}
this.appliedPaths.put(getLoginUrl(), null);
}
public String getUsernameParam() {
return usernameParam;
}
/**
* Sets the request parameter name to look for when acquiring the username. Unless overridden by calling this
* method, the default is <code>username</code>.
*
* @param usernameParam the name of the request param to check for acquiring the username.
*/
public void setUsernameParam(String usernameParam) {
this.usernameParam = usernameParam;
}
public String getPasswordParam() {
return passwordParam;
}
/**
* Sets the request parameter name to look for when acquiring the password. Unless overridden by calling this
* method, the default is <code>password</code>.
*
* @param passwordParam the name of the request param to check for acquiring the password.
*/
public void setPasswordParam(String passwordParam) {
this.passwordParam = passwordParam;
}
public String getRememberMeParam() {
return rememberMeParam;
}
/**
* Sets the request parameter name to look for when acquiring the rememberMe boolean value. Unless overridden
* by calling this method, the default is <code>rememberMe</code>.
* <p/>
* RememberMe will be <code>true</code> if the parameter value equals any of those supported by
* {@link org.apache.shiro.web.util.WebUtils#isTrue(javax.servlet.ServletRequest, String) WebUtils.isTrue(request,value)}, <code>false</code>
* otherwise.
*
* @param rememberMeParam the name of the request param to check for acquiring the rememberMe boolean value.
*/
public void setRememberMeParam(String rememberMeParam) {
this.rememberMeParam = rememberMeParam;
}
public String getFailureKeyAttribute() {
return failureKeyAttribute;
}
public void setFailureKeyAttribute(String failureKeyAttribute) {
this.failureKeyAttribute = failureKeyAttribute;
}
//拦截验证不通过都要走的onAccessDenied方法
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
if (log.isTraceEnabled()) {
log.trace("Login submission detected. Attempting to execute login.");
}
return executeLogin(request, response);
} else {
if (log.isTraceEnabled()) {
log.trace("Login page view.");
}
//allow them to see the login page ;)
return true;
}
} else {
if (log.isTraceEnabled()) {
log.trace("Attempting to access a path which requires authentication. Forwarding to the " +
"Authentication url [" + getLoginUrl() + "]");
}
//这就是重定向的方法
saveRequestAndRedirectToLogin(request, response);
return false;
}
}
/**
* This default implementation merely returns <code>true</code> if the request is an HTTP <code>POST</code>,
* <code>false</code> otherwise. Can be overridden by subclasses for custom login submission detection behavior.
*
* @param request the incoming ServletRequest
* @param response the outgoing ServletResponse.
* @return <code>true</code> if the request is an HTTP <code>POST</code>, <code>false</code> otherwise.
*/
@SuppressWarnings({"UnusedDeclaration"})
protected boolean isLoginSubmission(ServletRequest request, ServletResponse response) {
return (request instanceof HttpServletRequest) && WebUtils.toHttp(request).getMethod().equalsIgnoreCase(POST_METHOD);
}
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
String username = getUsername(request);
String password = getPassword(request);
return createToken(username, password, request, response);
}
protected boolean isRememberMe(ServletRequest request) {
return WebUtils.isTrue(request, getRememberMeParam());
}
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;
}
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e,
ServletRequest request, ServletResponse response) {
if (log.isDebugEnabled()) {
log.debug( "Authentication exception", e );
}
setFailureAttribute(request, e);
//login failed, let request continue back to the login page:
return true;
}
protected void setFailureAttribute(ServletRequest request, AuthenticationException ae) {
String className = ae.getClass().getName();
request.setAttribute(getFailureKeyAttribute(), className);
}
protected String getUsername(ServletRequest request) {
return WebUtils.getCleanParam(request, getUsernameParam());
}
protected String getPassword(ServletRequest request) {
return WebUtils.getCleanParam(request, getPasswordParam());
}
}
2、然后发现具体执行重定向的方法saveRequestAndRedirectToLogin(request, response);方法,继续对其跟踪发现最后就是调用的RedirectView类的renderMergedOutputModel方法进行重定向的
RedirectView.class:
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.shiro.web.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
/**
* View that redirects to an absolute, context relative, or current request
* relative URL, exposing all model attributes as HTTP query parameters.
* <p/>
* A URL for this view is supposed to be a HTTP redirect URL, i.e.
* suitable for HttpServletResponse's <code>sendRedirect</code> method, which
* is what actually does the redirect if the HTTP 1.0 flag is on, or via sending
* back an HTTP 303 code - if the HTTP 1.0 compatibility flag is off.
* <p/>
* Note that while the default value for the "contextRelative" flag is off,
* you will probably want to almost always set it to true. With the flag off,
* URLs starting with "/" are considered relative to the web server root, while
* with the flag on, they are considered relative to the web application root.
* Since most web apps will never know or care what their context path actually
* is, they are much better off setting this flag to true, and submitting paths
* which are to be considered relative to the web application root.
* <p/>
* Note that in a Servlet 2.2 environment, i.e. a servlet container which
* is only compliant to the limits of this spec, this class will probably fail
* when feeding in URLs which are not fully absolute, or relative to the current
* request (no leading "/"), as these are the only two types of URL that
* <code>sendRedirect</code> supports in a Servlet 2.2 environment.
* <p/>
* <em>This class was borrowed from a nearly identical version found in
* the <a href="http://www.springframework.org/">Spring Framework</a>, with minor modifications to
* avoid a dependency on Spring itself for a very small amount of code - we couldn't have done it better, and
* don't want to repeat all of their great effort ;).
* The original author names and copyright (Apache 2.0) has been left in place. A special
* thanks to Rod Johnson, Juergen Hoeller, and Colin Sampaleanu for making this available.</em>
*
* @see #setContextRelative
* @see #setHttp10Compatible
* @see javax.servlet.http.HttpServletResponse#sendRedirect
* @since 0.2
*/
public class RedirectView {
//TODO - complete JavaDoc
/**
* The default encoding scheme: UTF-8
*/
public static final String DEFAULT_ENCODING_SCHEME = "UTF-8";
private String url;
private boolean contextRelative = false;
private boolean http10Compatible = true;
private String encodingScheme = DEFAULT_ENCODING_SCHEME;
/**
* Constructor for use as a bean.
*/
@SuppressWarnings({"UnusedDeclaration"})
public RedirectView() {
}
/**
* Create a new RedirectView with the given URL.
* <p>The given URL will be considered as relative to the web server,
* not as relative to the current ServletContext.
*
* @param url the URL to redirect to
* @see #RedirectView(String, boolean)
*/
public RedirectView(String url) {
setUrl(url);
}
/**
* Create a new RedirectView with the given URL.
*
* @param url the URL to redirect to
* @param contextRelative whether to interpret the given URL as
* relative to the current ServletContext
*/
public RedirectView(String url, boolean contextRelative) {
this(url);
this.contextRelative = contextRelative;
}
/**
* Create a new RedirectView with the given URL.
*
* @param url the URL to redirect to
* @param contextRelative whether to interpret the given URL as
* relative to the current ServletContext
* @param http10Compatible whether to stay compatible with HTTP 1.0 clients
*/
public RedirectView(String url, boolean contextRelative, boolean http10Compatible) {
this(url);
this.contextRelative = contextRelative;
this.http10Compatible = http10Compatible;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
/**
* Set whether to interpret a given URL that starts with a slash ("/")
* as relative to the current ServletContext, i.e. as relative to the
* web application root.
* <p/>
* Default is "false": A URL that starts with a slash will be interpreted
* as absolute, i.e. taken as-is. If true, the context path will be
* prepended to the URL in such a case.
*
* @param contextRelative whether to interpret a given URL that starts with a slash ("/")
* as relative to the current ServletContext, i.e. as relative to the
* web application root.
* @see javax.servlet.http.HttpServletRequest#getContextPath
*/
public void setContextRelative(boolean contextRelative) {
this.contextRelative = contextRelative;
}
/**
* Set whether to stay compatible with HTTP 1.0 clients.
* <p>In the default implementation, this will enforce HTTP status code 302
* in any case, i.e. delegate to <code>HttpServletResponse.sendRedirect</code>.
* Turning this off will send HTTP status code 303, which is the correct
* code for HTTP 1.1 clients, but not understood by HTTP 1.0 clients.
* <p>Many HTTP 1.1 clients treat 302 just like 303, not making any
* difference. However, some clients depend on 303 when redirecting
* after a POST request; turn this flag off in such a scenario.
*
* @param http10Compatible whether to stay compatible with HTTP 1.0 clients.
* @see javax.servlet.http.HttpServletResponse#sendRedirect
*/
public void setHttp10Compatible(boolean http10Compatible) {
this.http10Compatible = http10Compatible;
}
/**
* Set the encoding scheme for this view. Default is UTF-8.
*
* @param encodingScheme the encoding scheme for this view. Default is UTF-8.
*/
@SuppressWarnings({"UnusedDeclaration"})
public void setEncodingScheme(String encodingScheme) {
this.encodingScheme = encodingScheme;
}
/**
* Convert model to request parameters and redirect to the given URL.
*
* @param model the model to convert
* @param request the incoming HttpServletRequest
* @param response the outgoing HttpServletResponse
* @throws java.io.IOException if there is a problem issuing the redirect
* @see #appendQueryProperties
* @see #sendRedirect
*/
//最终执行重定向的方法
public final void renderMergedOutputModel(
Map model, HttpServletRequest request, HttpServletResponse response) throws IOException {
// Prepare name URL.
StringBuilder targetUrl = new StringBuilder();
if (this.contextRelative && getUrl().startsWith("/")) {
// Do not apply context path to relative URLs.
targetUrl.append(request.getContextPath());
}
targetUrl.append(getUrl());
//change the following method to accept a StringBuilder instead of a StringBuilder for Shiro 2.x:
appendQueryProperties(targetUrl, model, this.encodingScheme);
sendRedirect(request, response, targetUrl.toString(), this.http10Compatible);
}
/**
* Append query properties to the redirect URL.
* Stringifies, URL-encodes and formats model attributes as query properties.
*
* @param targetUrl the StringBuffer to append the properties to
* @param model Map that contains model attributes
* @param encodingScheme the encoding scheme to use
* @throws java.io.UnsupportedEncodingException if string encoding failed
* @see #urlEncode
* @see #queryProperties
* @see #urlEncode(String, String)
*/
protected void appendQueryProperties(StringBuilder targetUrl, Map model, String encodingScheme)
throws UnsupportedEncodingException {
// Extract anchor fragment, if any.
// The following code does not use JDK 1.4's StringBuffer.indexOf(String)
// method to retain JDK 1.3 compatibility.
String fragment = null;
int anchorIndex = targetUrl.toString().indexOf('#');
if (anchorIndex > -1) {
fragment = targetUrl.substring(anchorIndex);
targetUrl.delete(anchorIndex, targetUrl.length());
}
// If there aren't already some parameters, we need a "?".
boolean first = (getUrl().indexOf('?') < 0);
Map queryProps = queryProperties(model);
if (queryProps != null) {
for (Object o : queryProps.entrySet()) {
if (first) {
targetUrl.append('?');
first = false;
} else {
targetUrl.append('&');
}
Map.Entry entry = (Map.Entry) o;
String encodedKey = urlEncode(entry.getKey().toString(), encodingScheme);
String encodedValue =
(entry.getValue() != null ? urlEncode(entry.getValue().toString(), encodingScheme) : "");
targetUrl.append(encodedKey).append('=').append(encodedValue);
}
}
// Append anchor fragment, if any, to end of URL.
if (fragment != null) {
targetUrl.append(fragment);
}
}
/**
* URL-encode the given input String with the given encoding scheme, using
* {@link URLEncoder#encode(String, String) URLEncoder.encode(input, enc)}.
*
* @param input the unencoded input String
* @param encodingScheme the encoding scheme
* @return the encoded output String
* @throws UnsupportedEncodingException if thrown by the JDK URLEncoder
* @see java.net.URLEncoder#encode(String, String)
* @see java.net.URLEncoder#encode(String)
*/
protected String urlEncode(String input, String encodingScheme) throws UnsupportedEncodingException {
return URLEncoder.encode(input, encodingScheme);
}
/**
* Determine name-value pairs for query strings, which will be stringified,
* URL-encoded and formatted by appendQueryProperties.
* <p/>
* This implementation returns all model elements as-is.
*
* @param model the model elements for which to determine name-value pairs.
* @return the name-value pairs for query strings.
* @see #appendQueryProperties
*/
protected Map queryProperties(Map model) {
return model;
}
/**
* Send a redirect back to the HTTP client
*
* @param request current HTTP request (allows for reacting to request method)
* @param response current HTTP response (for sending response headers)
* @param targetUrl the name URL to redirect to
* @param http10Compatible whether to stay compatible with HTTP 1.0 clients
* @throws IOException if thrown by response methods
*/
@SuppressWarnings({"UnusedDeclaration"})
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response,
String targetUrl, boolean http10Compatible) throws IOException {
if (http10Compatible) {
// Always send status code 302.
response.sendRedirect(response.encodeRedirectURL(targetUrl));
} else {
// Correct HTTP status code is 303, in particular for POST requests.
response.setStatus(303);
response.setHeader("Location", response.encodeRedirectURL(targetUrl));
}
}
}
3、然后对renderMergedOutputModel方法进行源码修改
在本地项目中创建一个和RedirectView类包名和类名完全一样的类
,然后把RedirectView类的内容复制粘贴过来:RedirectView类的包名是package org.apache.shiro.web.util
4、然后就可以改源码了(项目运行的时候就会使用我们定义的这个同名类,而不会执行shiro框架里面的那个类了)
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.shiro.web.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
/**
* View that redirects to an absolute, context relative, or current request
* relative URL, exposing all model attributes as HTTP query parameters.
* <p/>
* A URL for this view is supposed to be a HTTP redirect URL, i.e.
* suitable for HttpServletResponse's <code>sendRedirect</code> method, which
* is what actually does the redirect if the HTTP 1.0 flag is on, or via sending
* back an HTTP 303 code - if the HTTP 1.0 compatibility flag is off.
* <p/>
* Note that while the default value for the "contextRelative" flag is off,
* you will probably want to almost always set it to true. With the flag off,
* URLs starting with "/" are considered relative to the web server root, while
* with the flag on, they are considered relative to the web application root.
* Since most web apps will never know or care what their context path actually
* is, they are much better off setting this flag to true, and submitting paths
* which are to be considered relative to the web application root.
* <p/>
* Note that in a Servlet 2.2 environment, i.e. a servlet container which
* is only compliant to the limits of this spec, this class will probably fail
* when feeding in URLs which are not fully absolute, or relative to the current
* request (no leading "/"), as these are the only two types of URL that
* <code>sendRedirect</code> supports in a Servlet 2.2 environment.
* <p/>
* <em>This class was borrowed from a nearly identical version found in
* the <a href="http://www.springframework.org/">Spring Framework</a>, with minor modifications to
* avoid a dependency on Spring itself for a very small amount of code - we couldn't have done it better, and
* don't want to repeat all of their great effort ;).
* The original author names and copyright (Apache 2.0) has been left in place. A special
* thanks to Rod Johnson, Juergen Hoeller, and Colin Sampaleanu for making this available.</em>
*
* @see #setContextRelative
* @see #setHttp10Compatible
* @see javax.servlet.http.HttpServletResponse#sendRedirect
* @since 0.2
*/
public class RedirectView {
//TODO - complete JavaDoc
/**
* The default encoding scheme: UTF-8
*/
public static final String DEFAULT_ENCODING_SCHEME = "UTF-8";
private String url;
private boolean contextRelative = false;
private boolean http10Compatible = true;
private String encodingScheme = DEFAULT_ENCODING_SCHEME;
/**
* Constructor for use as a bean.
*/
@SuppressWarnings({"UnusedDeclaration"})
public RedirectView() {
}
/**
* Create a new RedirectView with the given URL.
* <p>The given URL will be considered as relative to the web server,
* not as relative to the current ServletContext.
*
* @param url the URL to redirect to
* @see #RedirectView(String, boolean)
*/
public RedirectView(String url) {
setUrl(url);
}
/**
* Create a new RedirectView with the given URL.
*
* @param url the URL to redirect to
* @param contextRelative whether to interpret the given URL as
* relative to the current ServletContext
*/
public RedirectView(String url, boolean contextRelative) {
this(url);
this.contextRelative = contextRelative;
}
/**
* Create a new RedirectView with the given URL.
*
* @param url the URL to redirect to
* @param contextRelative whether to interpret the given URL as
* relative to the current ServletContext
* @param http10Compatible whether to stay compatible with HTTP 1.0 clients
*/
public RedirectView(String url, boolean contextRelative, boolean http10Compatible) {
this(url);
this.contextRelative = contextRelative;
this.http10Compatible = http10Compatible;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
/**
* Set whether to interpret a given URL that starts with a slash ("/")
* as relative to the current ServletContext, i.e. as relative to the
* web application root.
* <p/>
* Default is "false": A URL that starts with a slash will be interpreted
* as absolute, i.e. taken as-is. If true, the context path will be
* prepended to the URL in such a case.
*
* @param contextRelative whether to interpret a given URL that starts with a slash ("/")
* as relative to the current ServletContext, i.e. as relative to the
* web application root.
* @see javax.servlet.http.HttpServletRequest#getContextPath
*/
public void setContextRelative(boolean contextRelative) {
this.contextRelative = contextRelative;
}
/**
* Set whether to stay compatible with HTTP 1.0 clients.
* <p>In the default implementation, this will enforce HTTP status code 302
* in any case, i.e. delegate to <code>HttpServletResponse.sendRedirect</code>.
* Turning this off will send HTTP status code 303, which is the correct
* code for HTTP 1.1 clients, but not understood by HTTP 1.0 clients.
* <p>Many HTTP 1.1 clients treat 302 just like 303, not making any
* difference. However, some clients depend on 303 when redirecting
* after a POST request; turn this flag off in such a scenario.
*
* @param http10Compatible whether to stay compatible with HTTP 1.0 clients.
* @see javax.servlet.http.HttpServletResponse#sendRedirect
*/
public void setHttp10Compatible(boolean http10Compatible) {
this.http10Compatible = http10Compatible;
}
/**
* Set the encoding scheme for this view. Default is UTF-8.
*
* @param encodingScheme the encoding scheme for this view. Default is UTF-8.
*/
@SuppressWarnings({"UnusedDeclaration"})
public void setEncodingScheme(String encodingScheme) {
this.encodingScheme = encodingScheme;
}
/**
*改动的源码
* @author wuyanjunxi
* @Description Ajax请求时重定向处理
* @date 2020/10/30
*
*/
/**
* Convert model to request parameters and redirect to the given URL.
*
* @param model the model to convert
* @param request the incoming HttpServletRequest
* @param response the outgoing HttpServletResponse
* @throws java.io.IOException if there is a problem issuing the redirect
* @see #appendQueryProperties
* @see #sendRedirect
*/
public final void renderMergedOutputModel(
Map model, HttpServletRequest request, HttpServletResponse response) throws IOException {
StringBuilder targetUrl = new StringBuilder();
if (getUrl().startsWith("/") && this.contextRelative) {
targetUrl.append(request.getContextPath());
}
targetUrl.append(getUrl());
appendQueryProperties(targetUrl, model, this.encodingScheme);
//如果是ajax请求
if("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))){
sendRedirect(response,targetUrl.toString());
}else {
sendRedirect(request, response, targetUrl.toString(), this.http10Compatible);
}
}
/**
*改动的源码
* @author wuyanjunxi
* @Description Ajax请求时重定向处理
* @date 2020/10/30
*
*/
private static void sendRedirect(HttpServletResponse response, String redirectUrl){
try {
//这里并没有进行重定向,而是把重定向的地址返回给前端,让前端做重定向
//重定向的地址
response.setHeader("redirectUrl", redirectUrl);
response.flushBuffer();
} catch (IOException ex) {
}
}
/**
* Append query properties to the redirect URL.
* Stringifies, URL-encodes and formats model attributes as query properties.
*
* @param targetUrl the StringBuffer to append the properties to
* @param model Map that contains model attributes
* @param encodingScheme the encoding scheme to use
* @throws java.io.UnsupportedEncodingException if string encoding failed
* @see #urlEncode
* @see #queryProperties
* @see #urlEncode(String, String)
*/
protected void appendQueryProperties(StringBuilder targetUrl, Map model, String encodingScheme)
throws UnsupportedEncodingException {
// Extract anchor fragment, if any.
// The following code does not use JDK 1.4's StringBuffer.indexOf(String)
// method to retain JDK 1.3 compatibility.
String fragment = null;
int anchorIndex = targetUrl.toString().indexOf('#');
if (anchorIndex > -1) {
fragment = targetUrl.substring(anchorIndex);
targetUrl.delete(anchorIndex, targetUrl.length());
}
// If there aren't already some parameters, we need a "?".
boolean first = (getUrl().indexOf('?') < 0);
Map queryProps = queryProperties(model);
if (queryProps != null) {
for (Object o : queryProps.entrySet()) {
if (first) {
targetUrl.append('?');
first = false;
} else {
targetUrl.append('&');
}
Map.Entry entry = (Map.Entry) o;
String encodedKey = urlEncode(entry.getKey().toString(), encodingScheme);
String encodedValue =
(entry.getValue() != null ? urlEncode(entry.getValue().toString(), encodingScheme) : "");
targetUrl.append(encodedKey).append('=').append(encodedValue);
}
}
// Append anchor fragment, if any, to end of URL.
if (fragment != null) {
targetUrl.append(fragment);
}
}
/**
* URL-encode the given input String with the given encoding scheme, using
* {@link URLEncoder#encode(String, String) URLEncoder.encode(input, enc)}.
*
* @param input the unencoded input String
* @param encodingScheme the encoding scheme
* @return the encoded output String
* @throws UnsupportedEncodingException if thrown by the JDK URLEncoder
* @see java.net.URLEncoder#encode(String, String)
* @see java.net.URLEncoder#encode(String)
*/
protected String urlEncode(String input, String encodingScheme) throws UnsupportedEncodingException {
return URLEncoder.encode(input, encodingScheme);
}
/**
* Determine name-value pairs for query strings, which will be stringified,
* URL-encoded and formatted by appendQueryProperties.
* <p/>
* This implementation returns all model elements as-is.
*
* @param model the model elements for which to determine name-value pairs.
* @return the name-value pairs for query strings.
* @see #appendQueryProperties
*/
protected Map queryProperties(Map model) {
return model;
}
/**
* Send a redirect back to the HTTP client
*
* @param request current HTTP request (allows for reacting to request method)
* @param response current HTTP response (for sending response headers)
* @param targetUrl the name URL to redirect to
* @param http10Compatible whether to stay compatible with HTTP 1.0 clients
* @throws IOException if thrown by response methods
*/
@SuppressWarnings({"UnusedDeclaration"})
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response,
String targetUrl, boolean http10Compatible) throws IOException {
if (http10Compatible) {
// Always send status code 302.
response.sendRedirect(response.encodeRedirectURL(targetUrl));
} else {
// Correct HTTP status code is 303, in particular for POST requests.
response.setStatus(303);
response.setHeader("Location", response.encodeRedirectURL(targetUrl));
}
}
}
2>前端处理:
1、在全局js中添加如下代码:
function redirect(xhr) {
var url = xhr.getResponseHeader("redirectUrl");
if((url != "")){
var win = window;
while(win != win.top){
win = win.top;
}
win.location.href = url;
}
}
$(function () {
//给document设置ajax的回调方法complete
$(document).ajaxComplete(function (event, xhr, settings) {
redirect(xhr);
})
})
上面的代码最终实现的效果类似这样:
$.ajax({
type : "POST", //提交方式
url:"findbyid",
dataType:"json",
data:{
"_id":funnel_id
},
success:function(funnel) {
$("#idField2").val(funnel.idField);
},
complete(XMLHttpRequest, status){//请求完成后最终执行参数
debugger;
var url = XMLHttpRequest.getResponseHeader("redirectUrl");
if((url != "")){
var win = window;
while(win != win.top){
win = win.top;
}
win.location.href = url;
}
},
});
至此shiro登录授权认证失败后,对ajax请求的无法重定向到登录页的问题就已经解决了