在spring过滤器中解决multipart / form-data请求

我正在尝试在Spring MVC 3中编写和开发自己的CSRF过滤器(有一些额外的培训使我可以这样做,所以请不要建议我使用Spring

Security。我知道,谢谢!!)

我的过滤器适用于除具有enctype =“ multipart / form-

data”之外的所有形式,因此实际上我无法从常规HttpServletRequest获取请求参数。

香港专业教育学院试图将其强制转换为MultipartHttpServletRequest,但我发现我也不能这样做。

请注意,我的目标不是获取文件,而只是获取名为“ csrf”的简单表单输入。我已经用我的表格上传了文件。

到目前为止,这是我的代码:

public class CSRFilter extends GenericFilterBean {

@Override

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) req;

HttpServletResponse response = (HttpServletResponse) res;

CSRF csrf = new CSRF(req);

if(csrf.isOk()){

chain.doFilter(req, res);

}else {

//todo : Show Error Page

String redirect = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/access-forbidden";

response.sendRedirect(redirect);

}

}

}

public class CSRF {

HttpServletRequest request;

ServletRequest req;

String token;

boolean ok;

private static final Logger logger = Logger.getLogger(CSRF.class);

public CSRF(ServletRequest request) {

this.request = (HttpServletRequest) request;

this.req = request;

init();

}

public CSRF() {

}

public void setRequest(HttpServletRequest request) {

this.request = (HttpServletRequest) request;

this.req = request;

init();

}

private void init() {

if (request.getMethod().equals("GET")) {

generateToken();

addCSRFTokenToSession();

addCSRFTokenToModelAttribute();

ok = true;

} else if (request.getMethod().equals("POST")) {

if (checkPostedCsrfToken()) {

ok = true;

}

}

}

private void generateToken() {

String token;

java.util.Date date = new java.util.Date();

UUID uuid = UUID.randomUUID();

token = uuid.toString() + String.valueOf(new Timestamp(date.getTime()));

try {

this.token = sha1(token);

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

this.token = token;

}

}

private void addCSRFTokenToSession() {

request.getSession().setAttribute("csrf", token);

}

private void addCSRFTokenToModelAttribute() {

request.setAttribute("csrf", token);

}

private boolean checkPostedCsrfToken() {

System.out.println("____ CSRF CHECK POST _____");

if (request.getParameterMap().containsKey("csrf")) {

String csrf = request.getParameter("csrf");

if (csrf.equals(request.getSession().getAttribute("csrf"))) {

return true;

}

}else {

//Check for multipart requests

MultipartHttpServletRequest multiPartRequest = new DefaultMultipartHttpServletRequest((HttpServletRequest) req);

if (multiPartRequest.getParameterMap().containsKey("csrf")) {

String csrf = multiPartRequest.getParameter("csrf");

if (csrf.equals(request.getSession().getAttribute("csrf"))) {

return true;

}

}

}

log();

return false;

}

private void log() {

HttpSession session = request.getSession();

String username = (String) session.getAttribute("username");

if(username==null){

username = "unknown (not logged in)";

}

String ipAddress = request.getHeader("X-FORWARDED-FOR");

if (ipAddress == null) {

ipAddress = request.getRemoteAddr();

}

String userAgent = request.getHeader("User-Agent");

String address = request.getRequestURI();

System.out.println("a CSRF attack detected from IP: " + ipAddress + " in address \"" + address + "\" - Client User Agent : " + userAgent + " Username: " + username);

logger.error("a CSRF attack detected from IP: " + ipAddress + " in address \"" + address + "\" - Client User Agent : " + userAgent + " Username: " + username);

}

public boolean isOk() {

return ok;

}

static String sha1(String input) throws NoSuchAlgorithmException {

MessageDigest mDigest = MessageDigest.getInstance("SHA1");

byte[] result = mDigest.digest(input.getBytes());

StringBuffer sb = new StringBuffer();

for (int i = 0; i < result.length; i++) {

sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));

}

return sb.toString();

}

}

我的调度员中也有此行:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

<!-- one of the properties available; the maximum file size in bytes -->

<property name="maxUploadSize" value="40000000"/>

</bean>

我也使用springMultipartResolver过滤器…

<filter>

<display-name>springMultipartFilter</display-name>

<filter-name>springMultipartFilter</filter-name>

<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>springMultipartFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

</filter>

我得到java.lang.IllegalStateException: Multipart request not

initialized的异常当我尝试它的multipart / form-data的形式。

我看了很多互联网上的例子。它们中的大多数用于文件上传目的,对我无济于事,我还尝试了其他方法将HttpServletRequest强制转换为其他任何可以解决我的多部分请求的对象,但是我无法成功。

我该怎么做 ?

谢谢。

回答:

您不能转换HttpServletRequestMultipartHttpServletRequest,因为您首先必须解决您的请求。

我使用CommonsMultipartResolverClass并MultipartHttpServletRequest使用commonsMultipartResolver.resolveMultipart(request)其中request是type的方法HttpServletRequest

因此,这是我的 类checkPostedCsrfToken()方法:

private boolean checkPostedCsrfToken() {

if (request.getParameterMap().containsKey("csrf")) {

String csrf = request.getParameter("csrf");

if (csrf.equals(request.getSession().getAttribute("csrf"))) {

return true;

}

} else if (request.getContentType() != null && request.getContentType().toLowerCase().contains("multipart/form-data")) {

CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();

MultipartHttpServletRequest multipartRequest = commonsMultipartResolver.resolveMultipart(request);

if (multipartRequest.getParameterMap().containsKey("csrf")) {

String csrf = multipartRequest.getParameter("csrf");

if (csrf.equals(request.getSession().getAttribute("csrf"))) {

return true;

}

}

}

log();

return false;

}

但是,请注意,您将丢失所有请求参数和数据。因此,您必须扩展HttpServletRequestWrapper类以读取请求字节,并使用它们获取参数,如果对您而言重要的是参数不会丢失抛出筛选器链。

这是我在StackOverflow中找到的一个好帮手类,(我再也找不到问题了,如果找到它,我将对其进行编辑)。

public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {

private ByteArrayOutputStream cachedBytes;

public MultiReadHttpServletRequest(HttpServletRequest request) {

super(request);

}

@Override

public ServletInputStream getInputStream() throws IOException {

if (cachedBytes == null)

cacheInputStream();

return new CachedServletInputStream();

}

@Override

public BufferedReader getReader() throws IOException{

return new BufferedReader(new InputStreamReader(getInputStream()));

}

private void cacheInputStream() throws IOException {

/* Cache the inputstream in order to read it multiple times. For

* convenience, I use apache.commons IOUtils

*/

cachedBytes = new ByteArrayOutputStream();

IOUtils.copy(super.getInputStream(), cachedBytes);

}

/* An inputstream which reads the cached request body */

public class CachedServletInputStream extends ServletInputStream {

private ByteArrayInputStream input;

public CachedServletInputStream() {

/* create a new input stream from the cached request body */

input = new ByteArrayInputStream(cachedBytes.toByteArray());

}

@Override

public int read() throws IOException {

return input.read();

}

}

}

现在您要做的就是在filter中使用MultiReadHttpServletRequest而不是normal HttpServletRequest

public class CSRFilter extends GenericFilterBean {

@Override

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) req;

HttpServletResponse response = (HttpServletResponse) res;

MultiReadHttpServletRequest multiReadHttpServletRequest = new MultiReadHttpServletRequest(request);

CSRF csrf = new CSRF(multiReadHttpServletRequest);

if(csrf.isOk()){

chain.doFilter(multiReadHttpServletRequest, res);

}else {

//todo : Show Error Page

String redirect = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/access-forbidden";

response.sendRedirect(redirect);

}

}

}

我希望这可以帮助某人:)

以上是 在spring过滤器中解决multipart / form-data请求 的全部内容, 来源链接: utcz.com/qa/428828.html

回到顶部