前言:前后端分离,业务分离,网关路由等已经成为当下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. 移动端1px细线解决方案总结

    现在的PM和UI总以看app的眼光看html5, html页面要做的专业美观,而且必须很精细. 去年的时候UI就告诉我h5上的边框线太粗,把整站都给拉low了. 当时工期紧就没太在意1px粗细, 好在 ...

  2. Object-C-Foundation-NSNuber

    NSNumber 是一个数值类型封装起来的数值. 装箱:基础类型->对象类型 NSNumber *number=[NSNumber numberWithInt:12]; 拆箱:对象类型-> ...

  3. Object-C-block

    块是对c语言的一种扩展语法 块看起来像函数,不同的是,快可以直接写在函数内部 块能够作为参数传递给函数或者方法 void sayHello(){NSLog(@"hello!");} ...

  4. Javassist注解(Annotation)的使用:CXF WebService动态生成

    设计一个对接系统,通过动态模型的增删改触发业务系统相应服务的调用.模型增删改方法动态发布为WebService服务.WebService服务采用CXF发布,动态类生成采用Javassist.由于Web ...

  5. QAQ的LIS树 QAQ的LIS树2 题解报告

    这两道题实际上考试的时候是一道题OwO 太可怕了,忙了我三个多小时,写了整整7K 这个题两个询问关联性不强,所以分开来考虑 QAQ的LIS树 考虑如何用dp求解答案 设dp(v)表示v到根的修改后的序 ...

  6. apache中的https设置基于阿里云免费ssl服务

    环境是:debian7+apache2.2+阿里云免费ssl服务,站点以前的http已经在运行了, 1.开通阿里云免费SSL&DNS解析配置 购买位置:打开阿里云找到“产品”-“安全”-“CA ...

  7. Git在windows下上传文件至github流程

    github是开发者分享的一个平台,这里不多说,想要上传文件至github需要有一个开发者账号,还需要在windows下安装好了git. 做好准备工作之后,接下来操作 一:登录github,创建项目 ...

  8. 20145317彭垚 MSF基础应用

    20145317彭垚 MSF基础应用 基础问题回答 用自己的话解释什么是exploit,payload,encode? exploit就相当于是载具,将真正要负责攻击的代码传送到靶机中,我觉得老师上课 ...

  9. Python3基础 global 使函数中的局部变量升格为全局变量

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  10. JavaScript常用操作,常用类

    算术运算符 重点关注 算数,赋值,逻辑运算符,三目运算符 <!DOCTYPE html> <html> <head> <meta charset=" ...