前言:前后端分离,业务分离,网关路由等已经成为当下web application开发的流行趋势。前端以单页面路由为核心的框架为主体,可以单独部署在nodejs或nginx上。后端以springboot为代表的分布式微服务框架为主体,可以独立运行在任何端口上。相互通过符合restful规范的接口访问或数据交换。在这样的开发模式下,首先需要解决的就是由于跨域而引起的访问,cookie传递以及权限管理问题。本文以时下最流行的Angular2,Springboot,Zuul,Shiro为例,提供最佳实践。

一、一般访问

开发中首先遇到的问题就是由于前端运行端口和后端运行端口不一致所造成的跨域访问。推荐在Springboot项目上增加过滤器:

@WebFilter
public class CorsFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub } @Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
response.setHeader("Access-Control-Allow-Credentials","true");
chain.doFilter(req, res);
} @Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub } }

二、身份认证auth

当用户登录以后理论上我们可以在后端我们可以获取当前用户的session数据,可是依然存在问题。造成这个问题的主要原因是后端依靠sessionid来确认数据,正常情况下浏览器会将数据保存在cookie中,而在非跨域的环境中,浏览器的每一次访问都会携带自己的cookie信息。但是Angular2这样的异步框架http模块默认请求时不会携带cookie信息的。这个问题的解决方法是前端请求需要增加“withCredentials: true”字段:

httpOptions: {
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
withCredentials: true
}
this.http.get<Users>(global.loginUrl + 'getUsers', global.httpOptions);

仅仅如此还不够,如果我们的前端并不是直接访问后端服务,而是通过Zuul这样的网管路由做了代理访问。你会发现后端依然无法正确获取session。原因是Zuul默认是不转发请求头或会过滤掉一些重要的头信息。因此我们还需要在Zuul的配置文件中增加一条:

zuul:
routes:
<servername>
sensitiveHeaders: "*"

这样前端请求携带的cookie信息才会顺利被发送到后端服务,后端才能够获取到正确的session。

三、Shiro过滤器

准确的这个问题不是跨域造成的,根据目前HTML5的流行趋势,在发送Post和Put请求前会首先通过Options请求做探测。在没有配置Shiro过滤器的情况下,这都不是问题。可以一旦后端服务配置了根绝url的权限过滤,前端的请求又会出现问题。原因是Shiro的默认过滤器使用了重定向,而Options在重定向后认为地址不可达因此不会继续发送正确的请求。要解决这个问题,我们需要重写Shiro的FormAuthenticationFilter:

@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager, @Qualifier("authFilter") Filter filter) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, Filter> filters = new HashMap<>();
filters.put("authc", filter);
filters.put("roles", filter);
filters.put("perms", filter);
shiroFilterFactoryBean.setFilters(filters); Map<String, String> filterChainDefinitionMap = new HashMap<String, String>(); filterChainDefinitionMap.put("/*", "anon");
filterChainDefinitionMap.put("/auth/*", "authc");
filterChainDefinitionMap.put("/auth/admin/*", "roles[admin,administrator]");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
} @Bean("authFilter")
public Filter authenticationFilter() {
return new FormAuthenticationFilter() {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if (request instanceof HttpServletRequest) {
if (((HttpServletRequest) request).getMethod().toUpperCase().equals("OPTIONS")) {
return true;
}
}
return super.isAccessAllowed(request, response, mappedValue);
} @Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
};
}
}

当然Shiro也为我们预留了接口,我们只需要按照需求配置即可。

四、总结

当下流行的前后端分离框架跨域是我们遇到的第一个问题,我们可以在服务端配置允许跨域访问来解决,具体方法推荐使用WebFilter过滤器。但是默认的rest请求sessionid,因此我们还需要让前端在请求头携带cookie。另外如果我们在前端展示与后端服务之前使用了网关还需要让网关服务允许所有的请求头通过而不要进行过滤。最后如果我们还使用了安全框架就必须让基于url权限管理功能放行所有的Options请求,以便让前端不会误认为请求地址不可达。

Angular2,Springboot,Zuul,Shiro跨域CORS请求踩坑实录的更多相关文章

  1. zuul+security跨域Cors问题解决

    zuul+security跨域Cors问题解决 简介 场景 在服务后台都会出现跨域cors问题,不过一般spring解决起来比较方便,在框架+框架的基础上,问题就显得特别明显了,各种冲突,不了解源码的 ...

  2. SpringBoot2.x整合Shiro出现cors跨域问题(踩坑记录)

    1. Springboot如何跨域? 最简单的方法是: 定义一个配置CorsConfig类即可(是不是简单且无耦合到令人发指) @Configuration public class CorsConf ...

  3. springboot webapi 支持跨域 CORS

    1.创建corsConfig 配置文件 @Configuration public class corsConfig { @Autowired varModel varModel_; @Bean pu ...

  4. 004. 前端跨域资源请求: JSONP/CORS/反向代理

    1.什么是跨域资源请求? https://www.cnblogs.com/niuli1987/p/10252214.html 同源: 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有 ...

  5. SpringBoot设置支持跨域请求

    跨域:现代浏览器出全的考虑,在http/https请求时必须遵守同源策略,否则即使跨域的http/https 请求,默认情况下是被禁止的,ip(域名)不同.或者端口不同.协议不同(比如http.htt ...

  6. 跨域原因及SpringBoot、Nginx跨域配置

    目录 概述 简单请求 跨域解决方案 概述 SpringBoot跨域配置 Nginx跨域配置 概述 MDN文档 Cross-Origin Resource Sharing (CORS) 跨域的英文是Cr ...

  7. MVC跨域CORS扩展

    一般的基于浏览器跨域的主要解决方法有这么几种:1.JSONP       2.IFrame方式    3.通过flash实现  4.CORS跨域资源共享  ,这里我们主要关注的是在MVC里面的CORS ...

  8. 跨域post请求实现方案小结--转

    [名词解释] 跨域:https://developer.mozilla.org/en-US/docs/JavaScript/Same_origin_policy_for_JavaScript 同源策略 ...

  9. 跨域CORS

    一.跨域CORS是什么 当一个资源从与该资源本身所在的服务器的域或端口不同的域或不同的端口请求一个资源时,浏览器会发起一个跨域 HTTP 请求.出于安全考虑,浏览器会限制从脚本内发起的跨域HTTP请求 ...

随机推荐

  1. Leetcode: Reorder List && Summary: Reverse a LinkedList

    Given a singly linked list L: L0→L1→…→Ln-1→Ln, reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→… You must do th ...

  2. 服务器修改用户密码注意iis部署的网站问题

    当服务器修改用户密码时,需要修改iis上部署的跟此用户权限有关的所有网站,选择网站——右击——应用程序管理——高级设置——物理路径凭证——特定用户——修改用户名和密码.

  3. 圆的k次面积并

    搬运别人的 https://vjudge.net/problem/SPOJ-CIRUT //china no.1 #pragma comment(linker, "/STACK:102400 ...

  4. python插入排序算法总结

    插入排序算法总结: 插入算法的核心是 每次循环到一个数时,都认为这个数之前的数列都是排好序的,将一个数插入到已经排好序的有序数列中,从而得到一个新的.个数加一的有序数列. 过程:从第一个元素开始,第一 ...

  5. 百度地图api通过地址显示地图,白名单

    百度地图api通过地址显示地图,白名单 http://developer.baidu.com/map/jsdemo.htm#i7_1?qq-pf-to=pcqq.c2c---------------- ...

  6. web前端----jQuery动画效果

    动画效果 // 基本 show([s,[e],[fn]]) hide([s,[e],[fn]]) toggle([s],[e],[fn]) // 滑动 slideDown([s],[e],[fn]) ...

  7. 20145302张薇 《网络对抗技术》 web基础

    20145302张薇 <网络对抗> web基础 实验问题回答 1.什么是表单 表单在网页中主要负责数据采集功能:一般网页上需要用户输入.选择的地方都会用到表单 表单标签:即,用于确定表单所 ...

  8. 20145306 逆向与Bof基础

    逆向与Bof基础 实践 一 直接修改机器指令,改变程序执行流程 本次实践的对象是一个名为pwn1的linux可执行文件. 显任何用户输入的字符串. 该程序同时包含另一个代码片段,getShell,会返 ...

  9. 解决Eclipse 项目报错:Unbound classpath container: ‘JRE System Library [JavaSE-1.7]

    MyEclipse出现下面两条报错: The project cannot be built until build path errors are resolved HelloWord Unknow ...

  10. neuroph Perceptron Sample

    错误: Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory     ...