springBoot跨域解决

首先配置允许跨域

@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                .maxAge(3600);
    }
}

因项目需对用户校验,因此配置了过滤器,
然后出现问题:

  **1.过滤器拦截后,页面提示没有跨域
  2.在过滤器配置跨域后,返回responsebody是空的**

代码如下:


import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
@Component
@WebFilter(filterName = "sessionFilter", urlPatterns = {"/*"})
public class SessionFilter implements Filter {

    @Value("${manage.session.timeout}")
    private long timeout;

    private final ObjectMapper mapper = new ObjectMapper();

    //不需要登录就可以访问的路径(比如:注册登录等)
    String[] includeUrls = new String[]{
            "/web-manage/su/submitLogin", "/su/submitLogin"};

    /**
     * 登录校验
     *
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        log.info("Headers:{}", response.getHeader("Access-Control-Request-Headers"));
        //String origin = request.getHeader("Origin");
        //if (origin == null) {
        //    origin = request.getHeader("Referer");
        //}
         //response.setHeader("Access-Control-Allow-Origin", origin);
        //使用通配符responseBody是空的!放开上段代码后项目正常
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");
        response.setHeader("Access-Control-Expose-Headers", "*");
        String uri = request.getRequestURI();
        String jsessionId = "";

        log.info("uri :{}, request.getContentType(): {}", uri, request.getContentType());
        //是否需要过滤
        boolean needFilter = isNeedFilter(uri, includeUrls);
        if (!needFilter) {
            //不需要过滤直接传给下一个过滤器
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            Cookie[] cookies = request.getCookies();
            if (cookies == null || cookies.length == 0) {
                cookieNoJessionid(response);
            } else {
                for (Cookie cookie : cookies) {
                    if (CommonConstant.JSESSIONID.equals(cookie.getName())) {
                        jsessionId = cookie.getValue();
                        break;
                    }
                }

                log.info("ContentType:" + request.getContentType());


                if (request.getMethod().equals("OPTIONS")) {
                    response.setStatus(HttpStatus.OK.value());
                    return;
                }

                RequestWrapper requestWrapper = null;
                if (request instanceof HttpServletRequest) {
                    if ("POST".equals(request.getMethod().toUpperCase())
                            && request.getContentType() != null
                            && request.getContentType().contains("application/json")) {
                        requestWrapper = new RequestWrapper(request);
                    }
                }

                judgeLogin(jsessionId, response, request, requestWrapper, filterChain);
            }
        }
    }


    /**
     * 判断是否已登录
     *
     * @param jsessionId
     * @param response
     * @param request
     * @param requestWrapper
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    private void judgeLogin(String jsessionId, HttpServletResponse response, HttpServletRequest request,
                            RequestWrapper requestWrapper, FilterChain filterChain) throws IOException, ServletException {
        // 判断 jsessionId 是否为空
        if (StringUtils.isBlank(jsessionId)) {
            cookieNoJessionid(response);
        } else {
            // 获取ValueOperations bean
            ServletContext context = request.getServletContext();
            ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);
            ValueOperations valueOperations = (ValueOperations) ctx.getBean("valueOperations");

            // 获取用户信息
            String userBoStr = (String) valueOperations.get(RedisConstant.REDIS_LOGIN + jsessionId);
            SysUserBo sysUserBo = mapper.readValue(userBoStr, SysUserBo.class);
            if (sysUserBo != null) {
                filterChain.doFilter(request == null ? requestWrapper : request, response);
            } else {
                // 返回登录超时提醒
                response.setContentType("application/json");
                response.setCharacterEncoding("UTF-8");
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                response.getWriter().write(this.mapper.writeValueAsString(ResultUtil.errorResult(
                        ExceptionEnum.ERROR_PARAMETERS.getCode(), "jsessionid 登录超时")));
            }
        }
    }

    /**
     * cookie 无jsessionid
     * @param response
     * @throws IOException
     */
    private void cookieNoJessionid(HttpServletResponse response) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.getWriter().write(this.mapper.writeValueAsString(ResultUtil.errorResult(
                ExceptionEnum.ERROR_PARAMETERS.getCode(),
                "jsessionid 为空!")));
    }

    /**
     * @param uri
     * @Description: 是否需要过滤
     */
    public boolean isNeedFilter(String uri, String[] includeUrls) {
        for (String includeUrl : includeUrls) {
            if (includeUrl.equals(uri)) {
                return false;
            }
        }

        return true;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}

百度一波,给出的解释是:
出自:https://www.cnblogs.com/nopnog/articles/9133115.html
Access-Control-Allow-Origin 的正确玩法
  前端发起的跨域请求需要适当地响应 Access-Control-Allow-Origin 头。但是这个头目前并不支持部分通配符,无法匹配某个域名下的子域。直接使用星号又可能带来各种问题。更坑爹的是它还不支持设置多个值。那么如果一个后端程序用于多个域名的访问该怎么办呢?
  很多时候一套后端的程序都对应了多个调用方,它们使用的的域名不同,scheme 可能也不同。所以 Access-Control-Allow-Origin 的值没法写死一个域名。如果直接暴力地将其设置为「」,可能导致一些未被授权的域名也能请求到资源。而且当 Access-Control-Allow-Credentials 的值为 true 时会导致Access-Control-Allow-Origin 无法被设置为「」。
  正确的玩法应该是在后端程序中获取从 HTTP 请求头传过来的 Origin 字段,然后在程序中验证它的值是否合法,并且做出适当的响应。也就是说,可以不依赖前端的跨域限制,后端如果认为一个请求的 Origin 来自不正确的地方就直接毫不留情地 403 掉。其它情况如果没有 Origin 或者 Origin 正确则将 Origin 的值原原本本地放入 Access-Control-Allow-Origin 中响应回去。
  其实虽然这个问题可以完全通过后端解决,但我还是很费解规范中无法使用局部通配符,和无法配置多个值的设定。也许这么设计的目的就是希望后端直接 403,而不是让浏览器来拦截吧(反正让浏览器来拦截还需要额外的传输成本,有点浪费)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值