博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Angular2,Springboot,Zuul,Shiro跨域CORS请求踩坑实录
阅读量:4317 次
发布时间:2019-06-06

本文共 4394 字,大约阅读时间需要 14 分钟。

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

一、一般访问

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

@WebFilterpublic 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
(global.loginUrl + 'getUsers', global.httpOptions);

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

zuul:  routes:    
sensitiveHeaders: "*"

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

三、Shiro过滤器

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

@Configurationpublic class ShiroConfig {    @Bean    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager, @Qualifier("authFilter") Filter filter) {        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();        shiroFilterFactoryBean.setSecurityManager(securityManager);        Map
filters = new HashMap<>(); filters.put("authc", filter); filters.put("roles", filter); filters.put("perms", filter); shiroFilterFactoryBean.setFilters(filters); Map
filterChainDefinitionMap = new HashMap
(); 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请求,以便让前端不会误认为请求地址不可达。

转载于:https://www.cnblogs.com/learnhow/p/9975515.html

你可能感兴趣的文章
经典排序算法回顾:选择排序,快速排序
查看>>
BZOJ2213 [Poi2011]Difference 【乱搞】
查看>>
c# 对加密的MP4文件进行解密
查看>>
AOP面向切面编程C#实例
查看>>
AngularJs学习笔记-慕课网AngularJS实战
查看>>
数据库三大范式
查看>>
工作总结之二:bug级别、优先级别、bug状态
查看>>
访问修饰符、封装、继承
查看>>
更换pip源到国内镜像,提升pip下载速度.
查看>>
POJ 2265 Bee Maja (找规律)
查看>>
Kendo MVVM 数据绑定(七) Invisible/Visible
查看>>
[zz]kvm环境使用libvirt创建虚拟机
查看>>
bzoj1059 [ZJOI2007]矩阵游戏
查看>>
插入返回ibatis 的selectKey 实现插入数据后获得id
查看>>
vim 程序编辑器
查看>>
LIS(单调队列优化 C++ 版)(施工ing)
查看>>
刚接触Vuex
查看>>
四种加载React数据的技术对比(Meteor 转)
查看>>
Airthmetic_Approching
查看>>
操作文本文件
查看>>