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 异常信息 */@Overrideprotected 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整合Shiro 涉及跨域和@Cacheable缓存/@Transactional事务注解失效问题(五)