SpringBoot整合Shiro 涉及跨域和@Cacheable缓存/@Transactional事务注解失效问题
Posted 如幻行云
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot整合Shiro 涉及跨域和@Cacheable缓存/@Transactional事务注解失效问题相关的知识,希望对你有一定的参考价值。
1. 跨域(多出现在前后端分离项目中)
(1) 跨域介绍可参考:跨域(CORS)
(2) SpringBoot中解决跨域方式有:
A. 使用@CrossOrigin注解;
B. 实现Filter类,重写doFilter方法
package com.ruhuanxingyun.config; import cn.hutool.core.util.StrUtil; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebFilter(filterName = "CorsFilter") public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, OPTIONS, PUT, DELETE");
// 浏览器低版本不支持* response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "Authorization, Content-Type"); // 跨域时会发送option请求 if (StrUtil.equals(request.getMethod(), HttpMethod.OPTIONS.name())) { response.setStatus(HttpStatus.OK.value()); } else { chain.doFilter(req, res); } } }
但是SpringBoot整合Shiro后,注解跨域就失效了,原因:shiro的过滤器会在注解跨域处理之前执行,这就导致未允许跨域的请求先到达shiro过滤器,这样就会出现跨域错误
(3) 在shiro中实现跨域,有以下两种方式
A. 继承BasicHttpAuthenticationFilter类,重写preHandle方法
/**
* 提供跨域支持
*
* @param request 请求对象
* @param response 响应对象
* @return 允许跨域
* @throws Exception 异常信息
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, OPTIONS, PUT, DELETE");
// 浏览器低版本不支持*
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "Authorization, Content-Type");
// 跨域时会发送option请求
if (StrUtil.equals(httpServletRequest.getMethod(), HttpMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
B. 实现Filter类,重写doFilter方法(如上)
2. @Cacheable缓存/@Transactional事务注解失效
(1) 问题体现:缓存和事务注解失效的类,都是在shiro框架中(loginRealm、jwtRealm)使用过@Autowired注入的类,而其他service事务都可以正常使用
(2) 产生原因:在shiro中为了引入权限注解,配置了defaultAdvisorAutoProxyCreator和authorizationAttributeSourceAdvisor类,他们是通过AOP方式对@RequiredPermission类进行增强,生成对应的代理类对象,由于shiroFilterFactoryBean实现了factoryBean接口,所以会被提前初始化,所以引发所有相关的bean提前初始化,导致他们没有被事务AOP包裹着,从而引发事务无效的问题
(3) 解决方式
A. @Autowired + @Lazy注解 延时加载注入
B. 在Realm中直接使用mapper,而不是service
C. ApplicationContextRegister.getBean()方法,手动注入bean
以上是关于SpringBoot整合Shiro 涉及跨域和@Cacheable缓存/@Transactional事务注解失效问题的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot(十四):springboot整合shiro-登录认证和权限管理