Merge pull request #1081 from drypa/patch-5
typos fix & code formatting
This commit is contained in:
58
ru/04.4.md
58
ru/04.4.md
@@ -1,11 +1,11 @@
|
|||||||
# 4.4 Дублирование отправки
|
# 4.4 Дублирование отправки
|
||||||
|
|
||||||
Не знаю, встречали ли Вы, как на каком-либо блоге или форуме размещено несколько постов подряд с одинаковым содержимым, но я могу сказать Вам, что это происходит по причине того, что отправка постов дублируется пользователем. Это может произойти по многим причинам; иногда пользователь отправляет форму двойным щелчком, или он после отправки решает исправить содержимое поста и нажимает кнопку браузера "Назад". А иногда это - намереные действия злоумышленников. Понятно, что дублирование отправки может привести ко многим проблемам. Поэтому нам нужно принимать эффективные меры для его предотвращения.
|
Не знаю, встречали ли Вы, как на каком-либо блоге или форуме размещено несколько постов подряд с одинаковым содержимым, но я могу сказать Вам, что это происходит по причине того, что отправка постов дублируется пользователем. Это может произойти по многим причинам; иногда пользователь отправляет форму двойным щелчком, или он после отправки решает исправить содержимое поста и нажимает кнопку браузера "Назад". А иногда это - намеренные действия злоумышленников. Понятно, что дублирование отправки может привести ко многим проблемам. Поэтому нам нужно принимать эффективные меры для его предотвращения.
|
||||||
|
|
||||||
Решением этой задачи является добавление в форму скрытого поля с уникальным токеном и проверка этого токена перед перед обработкой введенных данных. А если для отправки формы Вы используете Ajax, можно после того, как данные отправлены, сделать кнопку отправки неактивной.
|
Решением этой задачи является добавление в форму скрытого поля с уникальным токеном и проверка этого токена перед обработкой введенных данных. А если для отправки формы Вы используете Ajax, можно после того, как данные отправлены, сделать кнопку отправки неактивной.
|
||||||
|
|
||||||
Давайте усовершенствуем пример из раздела 4.2:
|
Давайте усовершенствуем пример из раздела 4.2:
|
||||||
|
```html
|
||||||
<input type="checkbox" name="interest" value="football">Футбол
|
<input type="checkbox" name="interest" value="football">Футбол
|
||||||
<input type="checkbox" name="interest" value="basketball">Баскетбол
|
<input type="checkbox" name="interest" value="basketball">Баскетбол
|
||||||
<input type="checkbox" name="interest" value="tennis">Теннис
|
<input type="checkbox" name="interest" value="tennis">Теннис
|
||||||
@@ -13,35 +13,35 @@
|
|||||||
Пароль:<input type="password" name="password">
|
Пароль:<input type="password" name="password">
|
||||||
<input type="hidden" name="token" value="{{.}}">
|
<input type="hidden" name="token" value="{{.}}">
|
||||||
<input type="submit" value="Login">
|
<input type="submit" value="Login">
|
||||||
|
```
|
||||||
Для того, чтобы сгенерировать токен, мы используем хэш MD5 (временная отметка), и добавляем его как в скрытое поле формы ввода данных на стороне клиента, так и в сессионный куки на стороне сервера (см. Раздел 6). Мы можем использовать этот токен для того, чтобы проверить, отправлялись ли уже данные с этой формы:
|
Для того, чтобы сгенерировать токен, мы используем хэш MD5 (временная отметка), и добавляем его как в скрытое поле формы ввода данных на стороне клиента, так и в сессионный куки на стороне сервера (см. Раздел 6). Мы можем использовать этот токен для того, чтобы проверить, отправлялись ли уже данные с этой формы:
|
||||||
|
```Go
|
||||||
|
func login(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Println("method:", r.Method) // получаем метод запроса
|
||||||
|
if r.Method == "GET" {
|
||||||
|
crutime := time.Now().Unix()
|
||||||
|
h := md5.New()
|
||||||
|
io.WriteString(h, strconv.FormatInt(crutime, 10))
|
||||||
|
token := fmt.Sprintf("%x", h.Sum(nil))
|
||||||
|
|
||||||
func login(w http.ResponseWriter, r *http.Request) {
|
t, _ := template.ParseFiles("login.gtpl")
|
||||||
fmt.Println("method:", r.Method) // получаем метод запроса
|
t.Execute(w, token)
|
||||||
if r.Method == "GET" {
|
} else {
|
||||||
crutime := time.Now().Unix()
|
// запрос данных о входе
|
||||||
h := md5.New()
|
r.ParseForm()
|
||||||
io.WriteString(h, strconv.FormatInt(crutime, 10))
|
token := r.Form.Get("token")
|
||||||
token := fmt.Sprintf("%x", h.Sum(nil))
|
if token != "" {
|
||||||
|
// проверяем валидность токена
|
||||||
t, _ := template.ParseFiles("login.gtpl")
|
} else {
|
||||||
t.Execute(w, token)
|
// если нет токена, возвращаем ошибку
|
||||||
} else {
|
}
|
||||||
// запрос данных о входе
|
fmt.Println("username length:", len(r.Form["username"][0]))
|
||||||
r.ParseForm()
|
fmt.Println("username:", template.HTMLEscapeString(r.Form.Get("username"))) // печатаем на стороне сервера
|
||||||
token := r.Form.Get("token")
|
fmt.Println("password:", template.HTMLEscapeString(r.Form.Get("password")))
|
||||||
if token != "" {
|
template.HTMLEscape(w, []byte(r.Form.Get("username"))) // отвечаем клиенту
|
||||||
// проверяем валидность токена
|
|
||||||
} else {
|
|
||||||
// если нет токена, возвращаем ошибку
|
|
||||||
}
|
|
||||||
fmt.Println("username length:", len(r.Form["username"][0]))
|
|
||||||
fmt.Println("username:", template.HTMLEscapeString(r.Form.Get("username"))) // печатаем на стороне сервера
|
|
||||||
fmt.Println("password:", template.HTMLEscapeString(r.Form.Get("password")))
|
|
||||||
template.HTMLEscape(w, []byte(r.Form.Get("username"))) // отвечаем клиенту
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||

|

|
||||||
|
|
||||||
Рисунок 4.4 Содержимое браузера после добавления токена
|
Рисунок 4.4 Содержимое браузера после добавления токена
|
||||||
|
|||||||
Reference in New Issue
Block a user