Форум программистов, компьютерный форум, киберфорум
raiderx
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  

Как запретить множественную передачу данных с формы

Запись от raiderx размещена 05.02.2013 в 17:54
Показов 2425 Комментарии 0

Практически с любой формы (создания или редактирования) можно отправить данные дважды.
Для этого достаточно дважды (или более раз) нажать на кнопку сабмита данных.
В результате могут быть созданы две (или более) одинаковые сущности в системе.

В Struts есть встроенная возможность, чтобы избежать этого, и называется она Synchronizer Token.

Но я использую Spring Framework, а точнее Spring MVC.
В Spring MVC нет похожего механизма, поэтому я реализовал его сам.

На форму помещается специальны тэг, который создает скрытое поле с уникальным значением:
HTML5
1
<k:token/>
Это уникальное значение помещается не только в скрытое поле, но и в HTTP сессию пользователя.
Исходный код класса:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package org.raiderx.tags;
 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
 
public class SynchronizerTokenTag extends SimpleTagSupport {
 
    public static final String TOKEN_KEY = "_synchronizerToken";
 
    @Override
    public void doTag() throws JspException, IOException {
        PageContext context = (PageContext)getJspContext();
        JspWriter out = context.getOut();
        String token = nextToken();
 
        List<String> tokens = (List<String>)context.getSession().getAttribute(TOKEN_KEY);
        if (tokens == null) {
            tokens = new ArrayList<String>();
            context.getSession().setAttribute(TOKEN_KEY, tokens);
        }
        tokens.add(token);
 
        out.print(buildTag(TOKEN_KEY, token));
    }
 
    public static String nextToken() {
        long seed = System.currentTimeMillis();
        Random r = new Random();
        r.setSeed(seed);
        return Long.toString(seed) + Long.toString(Math.abs(r.nextLong()));
    }
 
    public static String buildTag(String name, String value) {
        StringBuilder sb = new StringBuilder();
        sb.append("<input type=\"hidden\" name=\"");
        sb.append(name);
        sb.append("\" value=\"");
        sb.append(value);
        sb.append("\"/>");
        return sb.toString();
    }
}
И объявление данного тэга:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
        version="2.1">
 
    <tlib-version>1.0</tlib-version>
    <short-name>mytags</short-name>
    <uri>http://raiderx.org/jsp/tags/mytags</uri>
 
    <tag>
        <name>token</name>
        <tag-class>org.raiderx.tags.SynchronizerTokenTag</tag-class>
        <body-content>empty</body-content>
    </tag>
 
</taglib>
Так же в систему добавлен специальный обработчик, которому передается управление еще до того, как запрос будет обработан соответствующим методом контроллера.
XML
1
2
3
4
<mvc:interceptors>
    . . .
    <bean class="org.raiderx.utils.CustomHandlerInterceptor"/>
</mvc:interceptors>
Этот обработчик проверяет, передан ли специальный параметр с уникальным значением.
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package org.raiderx.utils;
 
import org.raiderx.tags.SynchronizerTokenTag;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
 
public class CustomHandlerInterceptor extends HandlerInterceptorAdapter {
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getParameter(SynchronizerTokenTag.TOKEN_KEY);
        if (token == null) {
            return true;
        }
        List<String> tokens = (List<String>)request.getSession().getAttribute(SynchronizerTokenTag.TOKEN_KEY);
        if (tokens == null) {
            throw new RuntimeException("TokenTag does not work correctly, tokens are not placed into the session");
        }
        if (!tokens.contains(token)){
            throw new RuntimeException("You are trying to send the form data twice");
        }
        tokens.remove(token);
        return true;
    }
}
Если такой параметр есть, то проверяется, есть ли полученное уникальное значение в HTTP-сессии пользователя.
  • если такое значение есть, то оно удаляется из HTTP-сессии пользователя, и далее HTTP-запрос обрабатывается соответствующим контроллером и его методом (экшеном);
  • если такого значения в HTTP-сессии нет, то генерируется соответствующее исключение.

Теперь на любой форме я только добавляю разработанный мною тэг:
HTML5
1
<k:token/>
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Новые блоги и статьи
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru