產生異常的狀況:nginx配置了https,可是nginx轉發請求到web應用走的http,會話超時,shiro會重定向到登陸頁,這時重定向的是http地址,好比http://xxxxx/login/index ,瀏覽器會阻止這樣的請求(從https頁面發起http請求是非法的)。javascript
public class MyShiroAuthcFilter extends FormAuthenticationFilter { public MyShiroAuthcFilter(String loginUrl) { super(); setLoginUrl(loginUrl); } @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { if (isLoginRequest(request, response)) { return super.onAccessDenied(request, response); } else { if (isAjax((HttpServletRequest) request)) { // 處理ajax請求 HttpServletResponse httpServletResponse = WebUtils.toHttp(response); httpServletResponse.addHeader("REQUIRE_AUTH", "true"); // ajax全局設置中有用 httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value()); // 改變302狀態碼 } else { saveRequest(request); request.getRequestDispatcher(getLoginUrl()).forward(request, response); // 因爲是nginx轉發的,redirect 302會重定向到http協議,不是瀏覽器指望的https // saveRequestAndRedirectToLogin(request, response); } return false; } } private boolean isAjax(HttpServletRequest request) { String requestedWithHeader = request.getHeader("X-Requested-With"); return "XMLHttpRequest".equals(requestedWithHeader); } }
shiro的filter配置java
@Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { String loginUrl = "/login/index"; ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); Map<String, Filter> filters = shiroFilter.getFilters(); filters.put("anon", new AnonymousFilter()); filters.put("authc", new MyShiroAuthcFilter(loginUrl)); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/supervisor/**", "authc"); filterChainDefinitionMap.put("/**", "anon"); shiroFilter.setSecurityManager(securityManager); shiroFilter.setLoginUrl(loginUrl); shiroFilter.setUnauthorizedUrl("/login/unauthorized"); shiroFilter.setFilters(filters); shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilter; }
$.ajaxSetup({ complete: function (xhr, status) { if (xhr.getResponseHeader('REQUIRE_AUTH') == 'true') { alert("未登陸或登陸超時!"); window.top.location.href = getHost() + '/login/index'; return; } } });
<script type="text/javascript"> // 使登陸頁出如今「頂級」窗口,調整瀏覽器的url地址,上面的filter是forward到登陸頁的 if(window.top != window.self || location.pathname != '/login/index') { window.top.location = getHost() + '/login/index'; } </script>