解决shiro自定义filter后,ajax登录无法登录,并且无法显示静态资源的问题
这个问题困扰了我一天,看了下面两个文章,豁然开朗:
https://www.cnblogs.com/gj1990/p/8057348.html
https://412887952-qq-com.iteye.com/blog/2392741
按照如下方法即可解决无法显示静态资源问题:
一、让springboot拦截器来接管静态资源,同时在shiroconfig中通过new方式注册过滤器
1、代码一
1 import java.util.Arrays; 2 3 import org.slf4j.Logger; 4 import org.slf4j.LoggerFactory; 5 import org.springframework.context.annotation.Configuration; 6 import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 7 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 8 9 /** 10 * SpringBoot管理器 11 */ 12 @Configuration 13 public class WebMvcConfiguration implements WebMvcConfigurer { 14 15 private final Logger logger = LoggerFactory.getLogger(WebMvcConfiguration.class); 16 17 @Override 18 public void addInterceptors(InterceptorRegistry registry) { 19 registry.addInterceptor(new LoginRequiredInterceptor()).excludePathPatterns(Arrays.asList("/css/**", "/js/**","/img/**","/fonts/**")); 20 } 21 }
2、代码二
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; /** * 登录拦截器 * * */ public class LoginRequiredInterceptor extends HandlerInterceptorAdapter { private final Logger logger = LoggerFactory.getLogger(LoginRequiredInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { logger.info(request.getRequestURI()); return super.preHandle(request, response, handler); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { logger.info(request.getRequestURI()); super.afterCompletion(request, response, handler, ex); } }
三、shiro配置中使用new方式生成filter
filters.put("authc", new ExtendFormAuthenticationFilter()); filterChainDefinitionMap.put("/**", "user,authc");
四、自定义filter
import com.simon.common.util.R; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class ExtendFormAuthenticationFilter extends FormAuthenticationFilter { private static final Logger log = LoggerFactory.getLogger(FormAuthenticationFilter.class); /** * 表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。 * onAccessDenied是否执行取决于isAccessAllowed的值,如果返回true则onAccessDenied不会执行;如果返回false,执行onAccessDenied * 如果onAccessDenied也返回false,则直接返回,不会进入请求的方法(只有isAccessAllowed和onAccessDenied的情况下) * */ @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { if(this.isLoginRequest(request, response)) { if(this.isLoginSubmission(request, response)) { if(log.isTraceEnabled()) { log.trace("Login submission detected. Attempting to execute login."); } return this.executeLogin(request, response); } else { if(log.isTraceEnabled()) { log.trace("Login page view."); } return true; } } else { if(log.isTraceEnabled()) { log.trace("Attempting to access a path which requires authentication. Forwarding to the Authentication url [" + this.getLoginUrl() + "]"); } this.saveRequestAndRedirectToLogin(request, response); return false; } } /** * 当登录成功 * @param token * @param subject * @param request * @param response * @return * @throws Exception */ @Override protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; if (!"XMLHttpRequest".equalsIgnoreCase(httpServletRequest .getHeader("X-Requested-With"))) {// 不是ajax请求 issueSuccessRedirect(request, response); } else { httpServletResponse.setCharacterEncoding("UTF-8"); PrintWriter out = httpServletResponse.getWriter(); //out.println("{\"success\":true,\"message\":\"登入成功\"}"); out.println(R.ok()); out.flush(); out.close(); } return false; } /** * 当登录失败 * @param token * @param e * @param request * @param response * @return */ @Override protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { if (!"XMLHttpRequest".equalsIgnoreCase(((HttpServletRequest) request) .getHeader("X-Requested-With"))) {// 不是ajax请求 setFailureAttribute(request, e); return true; } try { response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); String message = e.getClass().getSimpleName(); if ("IncorrectCredentialsException".equals(message)) { out.println("{\"success\":false,\"message\":\"密码错误\"}"); } else if ("UnknownAccountException".equals(message)) { out.println("{\"success\":false,\"message\":\"账号不存在\"}"); } else if ("LockedAccountException".equals(message)) { out.println("{\"success\":false,\"message\":\"账号被锁定\"}"); } else { out.println("{\"success\":false,\"message\":\"未知错误\"}"); } out.flush(); out.close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } return false; } }
第二种方式就是“取消Filter自动注册,不会添加到FilterChain中“,方法如下:
一、定义过滤器,如上第四步
二、在shiroconfig中声明自定义FormAuthenticationFilter
@Bean public ExtendFormAuthenticationFilter getLoginAdviceFilter(){ ExtendFormAuthenticationFilter filter=new ExtendFormAuthenticationFilter(); filter.setRememberMeParam("username"); filter.setPasswordParam("password"); //对应前端的checkbox的name = rememberMe filter.setRememberMeParam("rememberMe"); filter.setLoginUrl(loginUrl); return filter; }
三、取消注册
@Bean public FilterRegistrationBean registrationBean(ExtendFormAuthenticationFilter customFormAuthenticationFilter){ FilterRegistrationBean registration = new FilterRegistrationBean(customFormAuthenticationFilter); registration.setEnabled(false);//怎么取消 Filter自动注册,不会添加到FilterChain中. return registration; }
通过以上步骤就实现了解决shiro自定义filter后,ajax登录无法登录,并且无法显示静态资源的问题