2016-06-19 2 views
0

Я разрабатываю маркерный шлюз api. Он в основном обеспечивает токен для аутентичных клиентов. Поэтому я не уверен, как удалить истекшие жетоны. Для каждого запроса я проверил, действителен ли токен или нет.Лучший способ удалить токены из базы данных

Option 1 is 
Mark status of token as expired in database table row. 
and create a scheduler to run in midnight to delete expired tokens. 


Option 2 is 
Delete the token from the row when its expired. 
In here No need to run a scheduler. 

Обычно этот шлюз API обрабатывает около 1000 запросов в секунду, и это будет увеличиваться с каждым днем.

Так что я не уверен, какой вариант я должен использовать.

Технология, которую я использовал, есть. Весна mvc, данные весны jpa и Postgre DB. Будет развернуто на сервере tomcat.

+0

Простым решением будет использование кварца. Затем вы можете запланировать задание, чтобы запустить время до момента удаления истекших токенов. Кварц также хорошо ладит с весной. – Jodevan

+0

Вариант 2 на самом деле не является решением. Это ваше требование. Итак, какое решение осталось, кроме решения 1? Почему бы вам не поставить дату истечения срока в сам токен. Тогда нет необходимости в базе данных. См. Https://jwt.io/ –

+0

Итак, скажем, до тех пор, пока не начнет запускаться планировщик, в базе данных в нем будет 1000 токенов, в этом случае программе необходимо выполнить поиск данного токена более чем 1000 записей.когда его увеличение до большего количества токенов повлияет на производительность? – Suranga

ответ

1

Ни один из двух вариантов особенно хорош, так как оба изменят строку таблицы и, следовательно, генерируют ввод-вывод. При 1000 q/s вам нужно лучшее решение. On 2ndQuadrant - это blog post on authenticating users through connection pooling в контексте безопасности на уровне строк. В блоге есть некоторые проблемы ИМХО и не относящиеся к делу материалы, поэтому я постараюсь переделать его здесь правильно (или прочитать мой комментарий к сообщению в блоге).

В Java - как и в большинстве других языков программирования и/или фреймворков - пул соединений является предпочтительным способом подключения к серверу базы данных по соображениям производительности. Существует неявный контракт, который приложение запрашивает экземпляр Connection из пула, использует его, а затем возвращает экземпляр в пул для некоторого другого потока. Удерживание на Connection не является вариантом, так как оно прерывает логику объединения. Так действуйте следующим образом:


Подключение объекта бассейн

Создание объекта пула соединений с базой данных кластера учетных данных. Эта роль должна быть GRANT изменена все необходимые привилегии для таблиц и других объектов.

Authentication

В приложении пользователь проверяет подлинность делает myapp_login(username, password) или что-то подобное, используя Connection из пула. В базе данных учетные данные проверяются по таблице users или независимо от того, что она вызывается в вашей настройке. Если совпадение найдено, создайте случайный токен и вставьте его в таблицу:

CREATE UNLOGGED TABLE sessions (
    token  text DEFAULT uuid_generate_v4()::text, 
    login_time timestamp DEFAULT CURRENT_TIME, 
    user_name integer, 
    ... 
); 

Добавить столько полей, сколько хотите. Я использую здесь uuid (приведенный к text, читайте дальше), но вы также можете указать md5() или использовать некоторую процедуру pg_crypto.

Эта таблица должна быть быстрой, так что это UNLOGGED. Это означает, что он не является аварийно-аварийным и будет усечен после некоторой ошибки сервера, но это не проблема: все сеансы базы данных в любом случае будут признаны недействительными. Кроме того, не ставьте никаких ограничений, как NOT NULL на таблицу, потому что единственный доступ к этой таблице осуществляется через функции, которые вы как разработчик, обычный пользователь никогда не затрагивает эту таблицу, и каждое ограничение связано с большим количеством циклов процессора.

myapp_login() функция выглядит примерно так:

CREATE FUNCTION myapp_login(uname text, password text) RETURNS text AS $$ 
DECLARE 
    t  text; 
BEGIN 
    PERFORM * FROM app_users WHERE username = uname AND pwd = password; 
    IF FOUND THEN 
     INSERT INTO sessions(user_name) VALUES (uname) RETURNING token INTO t; 
     EXECUTE format('SET SESSION "my_app.session_user" TO %s', t); 
     RETURN t; 
    END IF; 
    SET SESSION "my_app.session_user" = ''; 
    RETURN NULL; 
END; 
$$ LANGUAGE plpgsql STRICT SECURITY DEFINER; 
REVOKE EXECUTE ON FUNCTION myapp_login(text, text) FROM PUBLIC; 
GRANT EXECUTE ON FUNCTION myapp_login(text, text) TO myapp_role; 

Как вы можете видеть, token также устанавливается в переменной окружения с SET SESSION (которая нуждается в буквальное значение текста, следовательно uuid::text гипсе и EXECUTE команда), а затем возвращается вызывающему. Этот токен сеанса должен храниться где-то в вашем коде приложения на стороне Java.

Функция выполняет поиск по таблице app_users и INSERT на столе sessions. Первое дешево, второе дорого.

Резюме тот же сеанс для дальнейших запросов

Если ваше приложение пользователь нуждается в дальнейшем доступ к базе данных после первых запросов, а затем получить Connection экземпляр из пула соединений снова, но не называют myapp_ login() но myapp_resume(token) вместо , Эта последняя функция ищет маркер в таблице sessions (дешево) и, если найден, устанавливает переменную сеанса в этот новый токен. Вы также можете проверить, что значение login_time является последним, или установить его с помощью CURRENT_TIME, чтобы сохранить сеанс «живым» (дорогим) или сделать любой другой необходимый бизнес.

Хитрость заключается в том, чтобы возобновить сеанс как можно более тонкими, поскольку это может происходить много раз во время сеанса (с точки зрения приложения).

закрыть сеанс

Когда пользователь приложение сделано, сделайте myapp_logout(token) который удаляет строку из sessions таблицы, которая соответствует маркеру.


Сессии, которые не закрыты должным образом, не удаляются из sessions таблицы, но я бы не слишком беспокоиться о that.You может планировать работу, которая выполняется один раз в неделю, чтобы удалить все строки, которые старше 6 часов или около того. Это также позволит вам выяснить, откуда, например, возникает ошибка.

Последнее слово на token. A uuid - это просто случайное число, но вы также можете сделать хэш имени пользователя приложения с некоторыми случайными данными и использовать его, например, в RLS или в каком-либо другом режиме доступа на основе строк; сообщение в блоге, которое я ссылаюсь на выше, имеет хорошую информацию об этом. В приложении, которое я разработал, я связываю строку из таблицы users с тем, что пользователю разрешено видеть. В любом случае вы должны действительно взвесить pro и con: хэш, который может быть использован в RLS, звучит неплохо, но для этого требуется, чтобы хеш был пересчитан (что имеет тенденцию быть дорогим) и сравнивается с хэшем сессии по каждому запросу, повторный поиск по таблице пользователей также является накладными расходами. Установка другой переменной сеанса, которая может быть проверена во время запроса с current_setting(), может быть хорошей альтернативой.

0

Я думаю, что самый простой способ был бы таким. Когда вы создаете токен в своей базе данных, вы можете хранить время генерации. Таким образом, когда клиент отправляет запрос в вашу базу данных, вы можете проверить, истек ли срок его действия, и удалить его во время запроса.

Смежные вопросы