记录一次spring boot+vue前后端分离项目的跨域问题(移动端)

前言

该项目是一个springboot+vue前后端分离的项目,如果在PC端的话可以通过nginx反向代理来绕过跨域问题,甚至可以把前后台都部署到一个容器中(这样的话其实算不上是真正的前后台分离,只是前后台开发分离)。但是移动端是通过vue打包出来的apk,最后要安装到手机端的,这样就限制了通过容器的方法来解决跨域的问题。

在网上看了很多博文,基本都是给spring boot加配置类的方法来解决跨域的问题,但并不能没有真正起到作用。

正文

一、创建一个ShrioUserFilter继承UserFilter

1.处理options请求

2.设置响应头

3.如果需要浏览器创建cookie,后台 Access-control-Allow-Credentials 设置为true,并且前台也要设置withCredential为true

package com.pm.background.admin.common.intercept;

import com.alibaba.fastjson.JSONObject;
import org.apache.shiro.web.filter.authc.UserFilter;
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;
import java.io.PrintWriter;

public class ShiroUserFilter extends UserFilter {
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            setHeader(httpRequest,httpResponse);
            return true;
        }
        return super.preHandle(request,response);
    }

    /**
     * 该方法会在验证失败后调用,这里由于是前后端分离,后台不控制页面跳转
     * 因此重写改成传输JSON数据
     */
    @Override
    protected void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        saveRequest(request);
        setHeader((HttpServletRequest) request,(HttpServletResponse) response);
        PrintWriter out = response.getWriter();
        out.println(JSONObject.toJSONString("未登录"));
        out.flush();
        out.close();
    }

    /**
     * 为response设置header,实现跨域
     */
    private void setHeader(HttpServletRequest request,HttpServletResponse response){
         //跨域的header设置
        response.setHeader("Access-control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods", request.getMethod());
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
        //防止乱码,适用于传输JSON数据
        response.setHeader("Content-Type","application/json;charset=UTF-8"); response.setStatus(HttpStatus.OK.value());
    }


}

二、在ShiroConfig中添加ShiroUserFilter

/**
 * Copyright 2018 人人开源 http://www.renren.io
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at *

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.pm.background.admin.config; import com.pm.background.admin.common.intercept.GunsUserFilter; import com.pm.background.admin.common.intercept.ShiroUserFilter; import com.pm.background.admin.common.shiro.UserRealm; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.mgt.SessionManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; /** * Shiro的配置文件 * * @author Mark [email protected] * @since 3.0.0 2017-09-27 */ @Configuration public class ShiroConfig { @Bean("sessionManager") public SessionManager sessionManager(/*RedisShiroSessionDAO redisShiroSessionDAO, @Value("${beam.admin.redis-open}") boolean redisOpen, @Value("${beam.admin.shiro-redis}") boolean shiroRedis*/){ DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); //设置session过期时间为1小时(单位:毫秒),默认为30分钟 sessionManager.setGlobalSessionTimeout(60 * 60 * 1000); sessionManager.setSessionValidationSchedulerEnabled(true); sessionManager.setSessionIdUrlRewritingEnabled(false); //如果开启redis缓存且beam.admin.shiro-redis=true,则shiro session存到redis里 // if(redisOpen && shiroRedis){ // sessionManager.setSessionDAO(redisShiroSessionDAO); // } return sessionManager; } @Bean("securityManager") public SecurityManager securityManager(UserRealm userRealm, SessionManager sessionManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm); securityManager.setSessionManager(sessionManager); return securityManager; } @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); shiroFilter.setLoginUrl("/login"); shiroFilter.setUnauthorizedUrl("/"); //session过期拦截 HashMap myFilters = new HashMap<>(); myFilters.put("user", new GunsUserFilter()); /*这个地方将解决跨域的过滤器放到过滤器链当中 -- 跨域*/ myFilters.put("user", new ShiroUserFilter()); shiroFilter.setFilters(myFilters); Map filterMap = new LinkedHashMap<>(); /*swagger 资源过滤*/ filterMap.put("/swagger/**", "anon"); filterMap.put("/v2/api-docs", "anon"); filterMap.put("/swagger-ui.html", "anon"); filterMap.put("/webjars/**", "anon"); filterMap.put("/swagger-resources/**", "anon"); filterMap.put("/workorder/getManufactureOrders","anon"); filterMap.put("/turnorder/add","anon"); filterMap.put("/working/getList","anon"); filterMap.put("/warehousing/testQr","anon"); filterMap.put("/warehousing/checkQrCode/*","anon"); filterMap.put("/login/**", "anon"); //登陆 filterMap.put("/kaptcha", "anon"); //验证码 filterMap.put("/global/*", "anon"); //全局路径(错误或者超时) filterMap.put("/favicon.ico", "anon"); filterMap.put("/**", "user"); shiroFilter.setFilterChainDefinitionMap(filterMap); return shiroFilter; } @Bean("lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator(); proxyCreator.setProxyTargetClass(true); return proxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } }

三、添加配置类CrosConfig

package com.pm.background.common.config;

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 CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); //允许任何域名
        corsConfiguration.addAllowedHeader("*"); //允许任何头
        corsConfiguration.addAllowedMethod("*"); //允许任何方法

        corsConfiguration.setAllowCredentials(true);
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig()); //注册
        return new CorsFilter(source);
    }
}

  跨域问题大功告成,并且浏览器可携带cookie

你可能感兴趣的:(记录一次spring boot+vue前后端分离项目的跨域问题(移动端))