参考链接:http://www.itblg.com/Java/base/576b5011215b07ab03505aa5
1.解决思路
前端采用ajax请求的主要目的是控制页面渲染,应该返回统一格式的json数据交由前端控制。
2.代码
2.1 authc_filter
/**
* 登入过滤器
*/
@Slf4j
public class ShiroAuthcFilter extends FormAuthenticationFilter {
/**
* ajax请求,无session
* 默认:会重定向至LoginUrl,如果LoginUrl返回的是页面,则影响用户体验
*
* 修改:转发至:ajaxSessionError ,然后进行response处理
*/
private String ajaxSessionErrorForwardUrl;
/**
* 如果没有设置,则返回LoginUrl
* @return
*/
public String getAjaxSessionErrorForwardUrl() {
if (this.ajaxSessionErrorForwardUrl==null){
this.ajaxSessionErrorForwardUrl = getLoginUrl();
}
return ajaxSessionErrorForwardUrl;
}
public void setAjaxSessionErrorForwardUrl(String ajaxSessionErrorForwardUrl) {
this.ajaxSessionErrorForwardUrl = ajaxSessionErrorForwardUrl;
}
/**
* 转发至ajaxSessionErrorForwardUrl
* @param request
* @param response
* @throws Exception
*/
public void forwardToAjaxSessionError(ServletRequest request, ServletResponse response)throws Exception {
WebUtils.toHttp(request).getRequestDispatcher(getAjaxSessionErrorForwardUrl()).forward(request,response);
}
/**
* 保存,然后转发,方便controller获取returnUrl并发送至前端,交由前端控制处理如何跳转
* @param request
* @param response
* @throws Exception
*/
public void savedAndForwardToAjaxSessionError(ServletRequest request, ServletResponse response)throws Exception{
this.saveRequest(request);
this.forwardToAjaxSessionError(request,response);
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (this.isLoginRequest(request, response)) {
if (this.isLoginSubmission(request, response)) {
return this.executeLogin(request, response);
} else {
return true;
}
} else {
/**
* ajax 请求无session或者session失效
*/
if (isAjax(request)){
this.savedAndForwardToAjaxSessionError(request,response);
}else {
this.saveRequestAndRedirectToLogin(request, response);
}
return false;
}
}
/**
* 判断是否是ajax请求
* @param request
* @return
*/
private boolean isAjax(ServletRequest request) {
String header = WebUtils.toHttp(request).getHeader("X-Requested-With");
if ("XMLHttpRequest".equalsIgnoreCase(header)) {
return true;
}
return false;
}
}
2.2 shiro_config
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SessionsSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/");
Map<String,Filter> filterMap = CollectionUtil.newHashMap();
ShiroAuthcFilter authcFilter = new ShiroAuthcFilter();
authcFilter.setAjaxSessionErrorForwardUrl("/error/session");
filterMap.put("authc",authcFilter);
shiroFilterFactoryBean.setFilters(filterMap);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
for (String path:ShiroUtils.PERMISSION_ALL_PATH_STR) {
filterChainDefinitionMap.put(path,"anon");
}
filterChainDefinitionMap.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
2.3 error_controller
@RestController
@RequestMapping("/error")
public class ErrorController {
/**
* ResponseData 演示格式,自己定义
* @param request
* @return
*/
@RequestMapping("/session")
public ResponseData sessionExpire(HttpServletRequest request){
SavedRequest savedRequest = WebUtils.getSavedRequest(request);
Map paramsMap = new HashMap();
if (savedRequest!=null){
paramsMap.put("returnUri","/login?returnUri="+UrlUtil.encode(savedRequest.getRequestURI())+"?"+savedRequest.getQueryString());
}
return ResponseData.error(401,"session timeout",paramsMap);
}
}
2.4 测试无session情况下ajax请求
2.5 前端根据返回数据控制页面跳转
参考:http://www.itblg.com/Java/base/576b5011215b07ab03505aa5
其他未尽内容请参考以下源码:
org.apache.shiro.web.filter.authc.FormAuthenticationFilter
org.apache.shiro.web.util.WebUtils