方案一:代理服务器
使用代理服务器可以在开发环境解决跨域,但一旦打包放到springboot里,开发环境配置的代理服务器就不管用了。
所以axiso请求的base_url不能写死,需要动态获取。根据浏览器中输入的地址来获取base_url。
let SQIMS_request =axios.create({
baseURL: window.location.protocol+'//'+window.location.host,
})
若分离部署,如何设置本地的代理服务器?每次打包时根据项目修改项目上的ip地址?(暂未解决)
如何设置nginx的代理服务器?(暂未解决)
方案二:后端配置全局跨域
前端设置
let SQIMS_request =axios.create({
baseURL: window.location.protocol+'//'+window.location.host,
withCredentials:true //开启凭证,axios在请求的时候会携带 JSESSIONID,用以shiro验证。如无需验证,则不设置此项。配合后端全局跨域设置,也可解决跨域问题
})
后端设置
springboot+shiro 采用如下设置并将过滤器执行顺序调到最高,一定要高于shiroFilter
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsFilterConfig {
/**
* @Description :跨域访问过滤器,设置执行顺序
* @Date 19:55 2021/6/15 0015
* @return org.springframework.boot.web.servlet.FilterRegistrationBean<org.springframework.web.filter.CorsFilter>
**/
@Bean
public FilterRegistrationBean<CorsFilter> corsFilterRegistrationBean(){
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setAllowCredentials(true);
source.registerCorsConfiguration("/**", config); // CORS 配置对所有接口都有效
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
//设置执行顺序,数字越小越先执行
bean.setOrder(0);
return bean;
}
}
若采用
@Configuration
public class GlobalCorsConfig {
/**
* 允许跨域调用的过滤器
*/
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
//允许所有域名进行跨域调用
config.addAllowedOrigin("*");
//允许跨越发送cookie
config.setAllowCredentials(true);
//放行全部原始头信息
config.addAllowedHeader("*");
//允许所有请求方法跨域调用
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
这种方式,则会出现shiroFilter早于该过滤器执行,导致需要经过shiroFilter的跨域失败
若选用这种情况,需要在shiroFilter中,也设置跨域配置
import com.sqims.sqiot.commons.entity.FangResponse;
import com.sqims.sqiot.commons.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
public class ShiroFilter extends FormAuthenticationFilter {
/**
* 在访问controller前判断是否登录,返回json,不进行重定向。
*
* @param request
* @param response
* @return true-继续往下执行,false-该filter过滤器已经处理,不继续执行其他过滤器
* @throws Exception
*/
@Override
protected boolean onAccessDenied (ServletRequest request, ServletResponse response) throws IOException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
//这里是个坑,如果不设置的接受的访问源,那么前端都会报跨域错误,因为这里还没到corsConfig里面
setHeader(httpServletRequest, httpServletResponse);
httpServletResponse.setCharacterEncoding("UTF-8");
// 这里不能抛给全局异常处理,因为抛给全局异常的话,shiro会返回一个html
log.error("未登录或登录已失效,请重新登录!");
FangResponse fangResponse = FangResponse.unAuthentication("未登录或登录已失效,请重新登录!");
httpServletResponse.getWriter().write(JsonUtil.toJson(fangResponse));
return false;
}
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpServletRequest httpRequest = (HttpServletRequest) request;
setHeader(httpRequest, httpResponse);
//无条件放行OPTIONS
if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
return true;
}
return super.preHandle(request, response);
}
/**
* 为response设置header,实现跨域
*/
private void setHeader(HttpServletRequest request, HttpServletResponse response) {
log.info("ShiroFilter");
response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods","*");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Max-Age", "3600");
}