博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring boot 和 Shiro 做后台跨域访问权限控制遇到的问题
阅读量:6256 次
发布时间:2019-06-22

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

  最近在弄一个后台用Spring boot、Shiro、Spring data mybatis,前台用Angular 4的项目.在做权限控制的时候后台一直获取不到前台获取的数据(username, password, token等)。记录一下解决过程。

  首先为了解决密码登录和Token验证两种验证方法,所以自定义了一个JWTOrAuthenticationFilter来根据前台传来的数据判断选择哪一种登录方法()。

  当然想象是美好的,定义完成后发现每次访问时传入JWTOrAuthenticationFilter的onAccessDenied时传入的Request数据都是空的,前台调试发现请求时数据是发送了的。

  • JWTOrAuthenticationFilter访问异常

  首先配置了/login=anon期望访问正常登陆的时候不通过Shiro的过滤器,而是访问Controller中定义的login方法。但是调试发现登录时根本没有进入Controller中定义的login方法,而是直接进入了JWTOrAuthenticationFilter。

  Google一下找到一篇帖子( )。原来将自定义Shiro Filter注册为Spring Bean时,会被自动注册到全局的ApplicationFilterChain中,这个自定义的Filter无论如何都会执行,所以/login=anon配置失效了。

  修改办法:不显式的将 JWTOrAuthenticationFilter 注册为 Spring bean 。代码如下:

protected ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager                                             securityManager,ShiroFilterChainDefinition shiroFilterChainDefinition) {     ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();     filterFactoryBean.setLoginUrl(loginUrl);     filterFactoryBean.setSuccessUrl(successUrl);     filterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);     filterFactoryBean.setSecurityManager(securityManager);     filterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap());     Map
filters = new HashMap<>(); filters.put("authc", new JWTOrAuthenticationFilter(origin)); filterFactoryBean.setFilters(filters); return filterFactoryBean; }
  • JS的CROS请求的异常

  经过上面的修改,正常登录终于可以成功了,撒花。。。。 但是问题又来了。。登录是可以成功了, 其他请求发送Token验证时应该经过 JWTOrAuthenticationFilter 去调用Token的登录验证Realm了, 但是 JWTOrAuthenticationFilter 获取不到前台发送的Token, 也就是只能登录,其他什么都干不了......MDZZ。这个就很奇怪了......

  经过前台调试发现根本没有前台根本没有发送Token到服务端, 只发送了一个 Access-Control-Allow-Headers:token-key 。所以我就以为是前台添加token的时候有问题,翻来复去换了好多种添加header的方法,依然不行。但是很奇怪啊明明他把header的key "token-key" 发送了, 为什么不发送值呢。仔细又去看了CROS的介绍。原来CROS复杂请求时会先发送一个OPTIONS请求,来测试服务器是否支持本次请求,这个请求时不带数据的,请求成功后才会发送真实的请求。所以前面那个只发送key的问题是要确认服务器支不支持接收这个header。所以每次获取不到数据的请求都是OPTIONS请求?。所以我们要做的就是把所有的OPTIONS请求统统放行。

  做法是在 JWTOrAuthenticationFilter 中重写一个 preHandler 方法。 代码如下:

protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {       HttpServletRequest httpRequest = WebUtils.toHttp(request);       HttpServletResponse httpResponse = WebUtils.toHttp(response);       if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {           httpResponse.setHeader("Access-control-Allow-Origin", origin);           httpResponse.setHeader("Access-Control-Allow-Methods", httpRequest.getMethod());           httpResponse.setHeader("Access-Control-Allow-Headers", httpRequest.getHeader("Access-Control-Request-Headers"));           httpResponse.setStatus(HttpStatus.OK.value());           return false;       }       return super.preHandle(request, response);   }
  • 前台Response数据的问题

  上一步完成后,第一次OPTIONS请求成功,第二次真实请求也发送成功(状态为200),但是response里面没有数据。这就很尴尬了,调试代码发现数据查询成功,返回成功。但是前台就是没有数据, 并报错(No 'Access-Control-Allow-Origin' header is present on the requested resource)根据这个错误去查看第二次请求的 response headers 果然发现所有跨域相关的header都没了(Access-Control-Allow-sth),但是明明在Application添加了允许跨域的配置。这里好像失效了,于是换了种方法,加了个CrosFilter, 终于解决问题。。

package com.webapp.web.filter;        import org.springframework.beans.factory.annotation.Value;    import org.springframework.stereotype.Component;        import javax.servlet.*;    import javax.servlet.http.HttpServletRequest;    import javax.servlet.http.HttpServletResponse;    import java.io.IOException;        @Component    public class CorsFilter implements Filter {             @Value("${cors.origin}")         private String origin;                 @Override         public void init(FilterConfig filterConfig) throws ServletException {                 }                 @Override         public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {             HttpServletResponse httpResponse = (HttpServletResponse) response;             HttpServletRequest httpRequest = (HttpServletRequest) request;             httpResponse.setHeader("Access-Control-Allow-Origin", origin);             httpResponse.setHeader("Access-Control-Allow-Methods", httpRequest.getMethod());             httpResponse.setHeader("Access-Control-Max-Age", "3600");             httpResponse.setHeader("Access-Control-Allow-Headers", httpRequest.getHeader("Access-Control-Request-Headers"));             chain.doFilter(request, response);         }                 @Override         public void destroy() {                 }    }

  虽然Application里的配置为什么失效,暂时还没弄明白是为什么,可是程序终于是可以跑通了,撒花。。。。。??。下一步想弄明白Application中的配置为什么会失效

@Beanpublic class CorsConfigurerAdapter extends WebMvcConfigurerAdapter{     @Override public void addCorsMappings(CorsRegistry registry) {                       registry.addMapping("*").allowedOrigins(origin);     } }

转载地址:http://roxsa.baihongyu.com/

你可能感兴趣的文章
Tensorflow 之 TensorBoard可视化Graph和Embeddings
查看>>
jquery easyui里datagrid用法记录
查看>>
【转】C++标准转换运算符const_cast
查看>>
ssh密码
查看>>
常用的HTML富文本编译器UEditor、CKEditor、TinyMCE、HTMLArea、eWebEditor、KindEditor简介...
查看>>
【Saltstack】Saltstack简单说明
查看>>
[转]香农信息论与毒药称球问题
查看>>
HTTP Error 500.19
查看>>
我在博客园的这一年
查看>>
红黑树
查看>>
Jackson使用ObjectManage#readValue传入泛型T的问题
查看>>
Python正则表达式中的re.S的作用
查看>>
从零开始构建一个centos+jdk7+tomcat7的docker镜像文件
查看>>
Source Insight 中文注释为乱码解决办法(完美解决,一键搞定)
查看>>
【LoadRunner】安装LoadRunner
查看>>
Linux内存管理 (15)页面迁移
查看>>
在高并发、高负载的情况下,如何给表添加字段并设置DEFAULT值?
查看>>
Cocos2d-x 3.0final 终结者系列教程13-贪食蛇游戏案例(全)
查看>>
Nginx的try_files指令和命名location使用实例
查看>>
IO多路复用之select
查看>>