前言:前后端分离,业务分离,网关路由等已经成为当下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. react native android 编译

    修改 Maven 仓库地址 React Native 在初始化时会从 jcenter.binary.com 这个地方下载一些东西,网上搜索了一下,好像是在下载 Maven 相关的依赖. 针对全局进行修 ...

  2. #C++初学记录(算法4)

    A - Serval and Bus It is raining heavily. But this is the first day for Serval, who just became 3 ye ...

  3. MFC Ribbon界面设计

    Ribbon是类似于office2007样式的界面,它替代了传统的MFC程序里的菜单和工具栏 MFC默认生成的Ribbon功能少,需要我们自己添加一些控件和图片等元素使界面好看 看下面的一个界面,是V ...

  4. 20154312 曾林 EXP7 网络欺诈防范

    目录 1.基础问题回答 ----1.1.通常在什么场景下容易受到DNS spoof攻击 ----1.2.在日常生活工作中如何防范以上两攻击方法 2.实践总结与体会 3.实践过程记录 ----3.1.简 ...

  5. CAReplicatorLayer

    CAReplicatorLayer CAReplicatorLayer的目的是为了高效生成许多相似的图层.它会绘制一个或多个图层的子图层,并在每个复制体上应用不同的变换.看上去演示能够更加解释这些,我 ...

  6. python isinstance()与type()的区别

    例如在继承上的区别: isinstance() 会认为子类是一种父类类型,考虑继承关系. type() 不会认为子类是一种父类类型,不考虑继承关系. class A: pass class B(A): ...

  7. Python: 正则表达式匹配多行,实现多行匹配模式

    1) 点 (.)去匹配任意字符的时候,不能匹配换行符 在这个模式中(?:.|\n)是指定了一个非捕获组(仅仅用来做匹配,部能通过单独捕获或者编号的组) 2) re.DOTALL re.compile( ...

  8. IO(字符流)

        1. 由于Java采用16位的Unicode字符,因此需要基于字符的输入/输出操作.从Java1.1版开始,加入了专门处理字符流的抽象类Reader和Writer,前者用于处理输入,后者用于处 ...

  9. javaScript的内置对象以及一些常用的方法

    前几天,我们学习了JavaScript的入门课程,但是要想做网站,仅仅学会入门是不够的,今后的几天,我将带领大家精通JavaScript,希望大家好好学习! JS内置对象 String对象:字符串对象 ...

  10. 20162311 Hash 补分博客

    20162311 Hash 补分博客 一.任务详情 二.解题过程 除留余数法和拉链法都懂了,也都会做,主要是开放寻址法.课下查了一些资料,也问了老师才彻底理解 引用例子 引用网上的一个例子来理解 参考 ...