自定义过滤器Filter进行JWT登陆令牌验证并设置响应头实现跨域时跨域失效

##针对网络上各种”自定义过滤器Filter进行JWT登陆令牌验证并设置响应头实现跨域“时跨域失效问题详解

首先,使用Spring相关框架,Maven环境。

如若仅需要后台跨域设置,则使用下面方法1足以。若已存在已有的自定义过滤器,则方法1势必会和原有的过滤器引发冲突。详解如下:

解决跨域方法1(项目不包含任何自定义过滤器时可用):

在启动类中或@Configuration自定义配置类中使用@bean注册自定义配置 添加如下代码即可:


@Configuration
public class CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 1
        corsConfiguration.addAllowedHeader("*"); // 2
        corsConfiguration.addAllowedMethod("*"); // 3
        return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig()); // 4
        return new CorsFilter(source);
    }
}

解决跨域方法2(项目中已有自定义过滤器时可用,此处以JWT登陆令牌验证的自定义过滤器为例):

JWT登陆令牌验证完整版参考链接(包含跨域设置):http://blog.csdn.net/qq_21144985/article/details/79363524
已存在自定义过滤器时,在过滤器中重写的doFilter()中设置响应头即可。网络上普遍的代码如下:


@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
		throws JsonProcessingException, IOException {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		httpResponse.setHeader("Access-Control-Allow-Origin", "*"); 
		httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
		httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with");  
		httpResponse.setHeader("Access-Control-Allow-Methods", "OPTIONS,GET,POST,DELETE,PUT"); 
		chain.doFilter(request, response);
}

此方法笔者试了很多次均以失败告终。后改成如下代码遂得以解决。


@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
		throws JsonProcessingException, IOException {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		httpResponse.setHeader("Access-Control-Allow-Origin", "*"); 
		if("OPTIONS".equals(httpRequest.getMethod())) {
			httpResponse.setStatus(HttpStatus.SC_NO_CONTENT); //HttpStatus.SC_NO_CONTENT = 204
			httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
			httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, Token");  
			httpResponse.setHeader("Access-Control-Allow-Methods", "OPTIONS,GET,POST,DELETE,PUT"); 
		}
		chain.doFilter(request, response);
}

此处需要引入apahe commons HttpClient的一个jar包:


<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
</dependency>

为何上述第一种方式不能解决而第二种方式却可以解决呢?请参考如下文档:
https://segmentfault.com/a/1190000009971254
通过参考前辈的解决方案得知,浏览器发送请求时会将请求分为简单请求和预检请求。所有非get请求都是预检请求。

简单请求:浏览器进行一次请求获取服务端一次响应。
预检请求:首先先尝试发送一个method为options的请求进行预检。检测是否具有访问服务器资源的权限。返回200+的状态码即表示预检通过,前端在接收到此状态码之后将发送正式请求。

因此,结合实际测试我们得知,阻止我们正常响应的就是预检不通过。由预检不通过导致的跨域不通过。预检请求校验中就包含了跨域校验,所以预检通过时,即跨域成功。

此处需要提的一点是:前端浏览器设置跨域,本质是将预检请求改为简单请求。

所以在使用上面第一种响应头设置时,因为过滤器对webtoken的拦截,而预检请求均不会设置参数。而我们在进行登录令牌校验时,针对所有非放行接口的webtoken,当其值为空时均返回登录异常。所以每次都不会返回正常结果。于是浏览器得到的永远都是预检不通过。因此即使设置了响应头也无法跨域成功。因为预检不通过是不会发送正式请求的。

而即便进行了webtoken为空时放行,也会触发跨域校验导致跨域不通过。

明白了问题所在后,我们在webtoken校验之前首先判断请求是否为预检请求,然后将所有预检请求的状态码设置为正常响应。设置完成之后,浏览器每次使用预检请求时均可以得到正常结果,因此浏览器接下来就会发送正式请求。

但设置后依旧会发现无法成功,预检请求时获取webtoken值时报错。原因是因为,我们在设置响应头中的请求头时,没有对webtoken参数的key值进行配置。因此 我们修改这句话如下:


httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, Token");

在Headers跨域设置时将前端给request中的header中设置的webtoken的Key值在此添加上,表示header中可以有一个叫‘Token’的参数。

设置完成之后就在登录校验完全限制的情况下跨域成功了。

总结起来就是我们在进行跨域登录令牌校验时按照如下步骤放行:
1、放行所有预检请求。
2、放行所有配置的需要放行的请求。
3、进行webtoken的存在性校验。
4、进行webtoken内容解析校验。
5、放行满足3和4的请求。
6、其余请求均为异常请求返回异常信息。

如有疑问烦请@笔者 Q:980420579 Q群:697819474

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值