predis - redis con php
Implementar el control de inundaciones con redis (1)
Preferiría usar la función de vencimiento de la clave de Redis, en lugar de volver a implementar una.
Una alternativa más simple sería la siguiente:
- simplemente establece un valor simple, que es el número de intentos; utilice una clave construida en un patrón como "identificador": "tipo de evento":
SETNX <identifier>:<event type> 1
si la respuesta es 1, este es el primer intento, por lo que establece un tiempo de espera en esta clave:
EXPIRE <identifier>:<event type> <timeout in seconds>
de lo contrario, aumentará el número de intentos
INCR <identifier>:<event type>
La respuesta del INCR le dará el número de intentos durante la ventana, para que sepa si puede permitir la acción o no.
También puede usar un hash en lugar de un valor simple, si necesita almacenar más datos, como la cantidad máxima de intentos permitidos en la ventana de tiempo determinada. En este caso, probablemente usará HSETNX y HINCR.
Estoy tratando de reemplazar la implementación sql del servicio de control de inundaciones de Drupal 8 con una implementación basada en redis.
Ver https://github.com/drupal/drupal/blob/8.0.x/core/lib/Drupal/Core/Flood/DatabaseBackend.php
Los requisitos son los siguientes:
- Cada ocurrencia de una acción / evento (por ejemplo, intentar iniciar sesión) se registra con una fecha de caducidad, un identificador y una marca de tiempo
- Necesito poder evitar que se pueda hacer una determinada acción más de N veces en un marco de tiempo determinado.
- Quiero poder limpiar eventos caducados
- En caso de un umbral de 3 en 10 minutos, si el usuario lo intenta una vez, luego dos veces después de 5 minutos, se bloquea y puede volver a intentarlo una vez después de 5 minutos más. No 10. Si bien el segundo sería una forma válida de hacerlo, no es cómo funciona la implementación de sql o cómo esperan que funcione.
- Como puede ver en función de la API, tampoco sé al registrar el evento cuál es el umbral, solo sé el vencimiento de un solo evento.
Mis pensamientos sobre cómo implementar esto:
- Si, después de que N ocurrencias se deben bloquear durante el tiempo dado, entonces esto sería fácil con una sola TECLA para evento: identificador que se incrementa, una vez que se alcanza el máximo, se bloquea hasta que caduque nuevamente y cada INCR también actualizará el vencimiento (o no).
- Encontré muchas publicaciones que preguntaban sobre el vencimiento de las entradas de la lista, lo cual no es posible. Hay soluciones alternativas que utilizan conjuntos ordenados y eliminar por rango. La mayoría parece usar un solo conjunto global, pero luego no puedo contar fácilmente mi evento + identificador, creo.
Después de escribir todo esto, en realidad podría tener una idea de cómo podría funcionar, así que supongo que lo que estoy buscando es retroalimentación sobre si eso tiene sentido o si hay una manera más fácil.
Cada evento: combinación de identificador es una clave y contiene un conjunto ordenado. Eso usa la expiración como puntaje y como valor un valor único, posiblemente el tiempo de creación en microsegundos. Cuento los registros no caducados para detectar si se alcanzó el umbral. Estoy actualizando la caducidad de cada evento: identificador a la ventana de vencimiento proporcionada, por lo que se eliminará automáticamente asumiendo que un identificador / cliente determinado no se da por vencido y sigue intentándolo, sin llegar a la caducidad. ¿Vale la pena limpiar los registros dentro de un conjunto, por ejemplo, al hacer un nuevo registro? Parece ser bastante rápido, y también podría hacerlo solo algunas veces.