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

 

猜你喜欢

转载自www.cnblogs.com/ruhuanxingyun/p/12147918.html