使用thymeleaf和spring security提供的csrf方法
使用thymeleaf和spring security提供的csrf方法
只需要在html内的form在设置action时使用thymeleaf属性th:action即可
<form th:action="@{login}" method="post">
<p>
<label for="username">Username</label> <input type="text" id="username" name="username" />
</p>
<p>
<label for="password">Password</label> <input type="password" id="password" name="password" />
</p>
<button type="submit" class="btn">Log in</button>
</form>
自定义csrf校验
- spring security配置文件中去掉自带的csrf校验
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
...
http.csrf().disable();
...
}
...
/***
* 说明见步骤2
* @see <a href=
* "https://blog.eyallupu.com/2012/04/csrf-defense-in-spring-mvc-31.html">New
* in Spring MVC 3.1: CSRF Protection using
* RequestDataValueProcessor</a>
*/
@Bean
public CSRFRequestDataValueProcessor requestDataValueProcessor() {
return new CSRFRequestDataValueProcessor();
}
}
- 实现RequestDataValueProcessor接口,关键方法是
getExtraHiddenFields
,然后把它添加到spring security配置文件中(参照步骤1中代码)
package springSecurity.csrf;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
public class CSRFRequestDataValueProcessor implements RequestDataValueProcessor {
@Override
public String processAction(HttpServletRequest request, String action, String httpMethod) {
return action;
}
@Override
public String processFormFieldValue(HttpServletRequest request, String name, String value, String type) {
return value;
}
@Override
public Map<String, String> getExtraHiddenFields(HttpServletRequest request) {
Map<String, String> hiddenFields = new HashMap<String, String>();
hiddenFields.put(CSRFTokenManager.CSRF_PARAM_NAME, CSRFTokenManager.getTokenForSession(request.getSession()));
return hiddenFields;
}
@Override
public String processUrl(HttpServletRequest request, String url) {
return url;
}
}
- 添加自定义拦截器并添加到spring mvc配置文件中
package springSecurity.csrf;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import lombok.val;
public class CSRFHandlerInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
val me = request.getMethod();
if (!request.getMethod().equalsIgnoreCase("POST")) {
// Not a POST - allow the request
return true;
} else {
// This is a POST request - need to check the CSRF token
String sessionToken = CSRFTokenManager.getTokenForSession(request.getSession());
String requestToken = CSRFTokenManager.getTokenFromRequest(request);
if (sessionToken.equals(requestToken)) {
return true;
} else {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Bad or missing CSRF value");
return false;
}
}
}
}
@Configuration
@EnableWebMvc
@EnableGlobalMethodSecurity
@ComponentScan("service,servlet,controller,springSecurity")
public class AppcationContextConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware {
...
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CSRFHandlerInterceptor());
}
...
}
工具类CSRFTokenManager
package springSecurity.csrf;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class CSRFTokenManager {
static final String CSRF_PARAM_NAME = "CSRFToken";
private final static String CSRF_TOKEN_FOR_SESSION_ATTR_NAME = CSRFTokenManager.class.getName() + ".tokenval";
static String getTokenForSession(HttpSession session) {
String token = null;
// I cannot allow more than one token on a session - in the case of two
// requests trying to
// init the token concurrently.
// Notice: in real life I wouldn't synchronize on the session instance.
// This should be done on an attribute on the session. But for the
// blog demo this is fine
synchronized (session) {
token = (String) session.getAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME);
if (null == token) {
token = UUID.randomUUID().toString();
session.setAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME, token);
}
}
return token;
}
static String getTokenFromRequest(HttpServletRequest request) {
return request.getParameter(CSRF_PARAM_NAME);
}
private CSRFTokenManager() {
};
}
参考New in Spring MVC 3.1: CSRF Protection using RequestDataValueProcessor
Updated: 2022-12-10 17:49
Created: 2019-01-13 01:33