基于Spring Security+Spring MVC的web应用,为了防止跨站提交攻击,通常会配置csrf,即:

     <http ...>
...
<csrf />
</http>

如果应用中有Post方式访问的Rest服务(参考下面的代码),会很不幸的发现,所有POST方式请求的服务会调用失败。

     @RequestMapping(value = "/user/create", method = RequestMethod.POST)
@ResponseBody
public UserInfo createUser(@RequestBody(required = true) UserInfo user,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
...
}

原因在于:启用csrf后,所有http请求都被会CsrfFilter拦截,而CsrfFilter中有一个私有类DefaultRequiresCsrfMatcher

     private static final class DefaultRequiresCsrfMatcher implements RequestMatcher {
private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$"); /* (non-Javadoc)
* @see org.springframework.security.web.util.matcher.RequestMatcher#matches(javax.servlet.http.HttpServletRequest)
*/
public boolean matches(HttpServletRequest request) {
return !allowedMethods.matcher(request.getMethod()).matches();
}
}

从这段源码可以发现,POST方法被排除在外了,也就是说只有GET|HEAD|TRACE|OPTIONS这4类方法会被放行,其它Method的http请求,都要验证_csrf的token是否正确,而通常post方式调用rest服务时,又没有_csrf的token,所以校验失败。

解决方法:自己弄一个Matcher

 package com.cnblogs.yjmyzz.utils;

 import java.util.List;
import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import org.springframework.security.web.util.matcher.RequestMatcher; public class CsrfSecurityRequestMatcher implements RequestMatcher {
private Pattern allowedMethods = Pattern
.compile("^(GET|HEAD|TRACE|OPTIONS)$"); public boolean matches(HttpServletRequest request) { if (execludeUrls != null && execludeUrls.size() > 0) {
String servletPath = request.getServletPath();
for (String url : execludeUrls) {
if (servletPath.contains(url)) {
return false;
}
}
}
return !allowedMethods.matcher(request.getMethod()).matches();
} /**
* 需要排除的url列表
*/
private List<String> execludeUrls; public List<String> getExecludeUrls() {
return execludeUrls;
} public void setExecludeUrls(List<String> execludeUrls) {
this.execludeUrls = execludeUrls;
}
}

这里添加了一个属性execludeUrls,允许人为排除哪些url。

然后在配置文件里,这样修改:

     <http entry-point-ref="loginEntryPoint" use-expressions="true">
...
<intercept-url pattern="/rest/**" access="permitAll" />
...
<csrf request-matcher-ref="csrfSecurityRequestMatcher"/>
</http> <beans:bean id="csrfSecurityRequestMatcher" class="com.cnblogs.yjmyzz.utils.CsrfSecurityRequestMatcher">
<beans:property name="execludeUrls">
<beans:list>
<beans:value>/rest/</beans:value>
</beans:list>
</beans:property>
</beans:bean>

这里约定所有/rest/开头的都是Rest服务地址,上面的配置就把/rest/排除在csrf验证的范围之外了.

Spring Security笔记:解决CsrfFilter与Rest服务Post方式的矛盾的更多相关文章

  1. Spring Security笔记:HTTP Basic 认证

    在第一节 Spring Security笔记:Hello World 的基础上,只要把Spring-Security.xml里改一个位置 <http auto-config="true ...

  2. 【Spring学习笔记-MVC-4】SpringMVC返回Json数据-方式2

    <Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...

  3. 【Spring学习笔记-MVC-3】SpringMVC返回Json数据-方式1

    <Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...

  4. Spring Security笔记:自定义Login/Logout Filter、AuthenticationProvider、AuthenticationToken

    在前面的学习中,配置文件中的<http>...</http>都是采用的auto-config="true"这种自动配置模式,根据Spring Securit ...

  5. Spring Security笔记:Remember Me(下次自动登录)

    前一节学习了如何限制登录尝试次数,今天在这个基础上再增加一点新功能:Remember Me. 很多网站,比如博客园,在登录页面就有这个选项,勾选“下次自动登录”后,在一定时间段内,只要不清空浏览器Co ...

  6. Spring Security笔记:使用数据库进行用户认证(form login using database)

    在前一节,学习了如何自定义登录页,但是用户名.密码仍然是配置在xml中的,这样显然太非主流,本节将学习如何把用户名/密码/角色存储在db中,通过db来实现用户认证 一.项目结构 与前面的示例相比,因为 ...

  7. Spring Security笔记:Hello World

    本文演示了Spring Security的最最基本用法,二个页面(或理解成二个url),一个需要登录认证后才能访问(比如:../admin/),一个可匿名访问(比如:../welcome) 注:以下内 ...

  8. Spring Security笔记:登录尝试次数限制

    今天在前面一节的基础之上,再增加一点新内容,默认情况下Spring Security不会对登录错误的尝试次数做限制,也就是说允许暴力尝试,这显然不够安全,下面的内容将带着大家一起学习如何限制登录尝试次 ...

  9. Spring Security笔记:使用BCrypt算法加密存储登录密码

    在前一节使用数据库进行用户认证(form login using database)里,我们学习了如何把“登录帐号.密码”存储在db中,但是密码都是明文存储的,显然不太讲究.这一节将学习如何使用spr ...

随机推荐

  1. 学习 Mysql - 在linux上使用yum安装MySQL

    1.检查已经安装的mysql信息 yum list installed mysql*rpm -qa | grep mysql* 2.列出已安装和可安装的mysql信息 yum list mysql* ...

  2. 使用PL/SQL编写存储过程访问数据库

    一.实验目的 熟悉使用存储过程来进行数据库应用程序的设计. 二.实验内容 对学生-课程数据库,编写存储过程,完成下面功能: 1.统计离散数学的成绩分布情况,即按照各分数段统计人数: 2.统计任意一门课 ...

  3. 开源游戏“2048”IOS移植版

    简介: 这个游戏是我在今年(2014/05)课余时闲着无聊做的一个益智类小游戏,总共花了4个工作日才完成,为了游戏的效率,做了很多优化,目前在IE5以上浏览器能够流畅运行,运行时如果屏幕分辨率不兼容, ...

  4. 源码编译安装screen

    OS:Amazon Linux AMI 2015.09.2 (HVM) #sudo su #wget http://ftp.gnu.org/gnu/screen/screen-4.3.1.tar.gz ...

  5. 深入理解“HelloWorld”小程序

    对于每个Java程序员来说,HelloWorld是一个再熟悉不过的程序.它很简单,但是这段简单的代码能指引我们去深入理解一些复杂的概念.这篇文章,我将探索我们能从这段简单的代码中学到什么.如果你对He ...

  6. 【转发】Html5 File Upload with Progress

    Html5 File Upload with Progress               Posted by Shiv Kumar on 25th September, 2010Senior Sof ...

  7. oracle数据泵示例

    主要的导出示例: 1.导出指定表空间: expdp system/xxx DIRECTORY=dump_dir tableapace=xxx dumpfile=xxx_%DATE:~0,4%%DATE ...

  8. 学习myBatis - 如何配置myBatis

    这篇文章主要学习如何配置myBatis. 要学习新东西要讲究方法,要从三个层面去理解它:它是什么(what),为什么要学它(why),怎么用它(how).有了学习方法学习的效率才高. 1.myBati ...

  9. 烂泥:vcenter通过模板部署vm

    本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb. 前一篇文章我们介绍了有关vcenter5.5的安装与配置,这篇文章我们再来介绍下,如何 ...

  10. python入门综合

    #!/usr/bin/env python#-*-coding:utf-8-*- #以上是配置编写环境的开始   #第一行env表示运行当前环境变量内的python版本(2.x or 3.x)#第二行 ...