Pull to refresh
16K+
28
BugM@BugM

Уверенный пользователь ПК

11,7
Rating
22
Subscribers
Send message
Есть закон. Ссылку не дам, но формулируется так: «Пользователь может подписать только тот документ который он видит.»

Есть несколько типовых сценариев подписи pdf:
1. С сервера прилетает файл. Показывается на клиенте. По кнопке Подписать считаем хеш и подписываем.
2. С сервера прилетаем файл. Показываем его. По кнопке Подписать запрашиваем хеш с сервера и подписываем.
3. С сервера прилетает некое изображение документа. По кнопке Подписать запрашиваем хеш и подписываем.
4. По кнопке Подписать запрашиваем хеш и подписываем.

Сценарии идут в порядке понижения законности.
Первый абсолютно законен.
Второй относительно законен, но не имеет смысла. Хеш посчитать быстрее чем отрендерить документ.
Третий незаконен, но иногда бывает. Телефоны плохо дружат с большими файлами. Все выкручиваются как могут.
Четвертый абсолютно незаконен.

У вас статья о четвертом сценарии.
В процессе решения задачу решили усложнить для нас, и уменьшить объем передаваемых данных на клиент. Передавать только hash документа, но не сам документ.

Не надо так делать.
Вы в курсе что это все абсолютно незаконно? Нельзя подписывать ЭПЦ пользователя то что пользователь не видит.
И даже подменять файлики нельзя. То есть показать одно а подписать другое нельзя.
А вот я пошел честно и гуглить оптимальный алгоритм не стал. И без подсказки datacompboy до лучшего решения не догадался.
Ракетная посадка отнимает 30-45% ПН и экономически не рентабельна. Ступень можно приземлить только на парашюте с коррекцией траектории и потерей 15% ПН. Все остальное прожектерство.

А Маск в курсе?
Про переполнение в сложных случаях я ниже написал.
O(1) это для обычной вставки или удаления первого элемента LinkedHashMap

Зачем получать? Я честно нагуглил. Помню я это примерно так:
1. Это очень быстро вообще не паримся.
2. Это быстро. Если надо чтобы очень быстро было проверить это место.
3. Это медленно. Будет тормозить.
4. Это нереально медленно. Переписать при первой возможности.

Для собеседования в Гугле естественно не подойдет, но для повседневности достаточно.
Добавление и получение O(1) коллизий у нас нет или почти нет.
Удаление и по ttl и по памяти требующее полного прохода O(n). Зато не влияет на основные процессы и работает независимо.
Отслеживание памяти при втором проходе ничего.

Тогда при равномерном использовании и удалении самого старого берем LinkedHashMap и просто удаляем первый элемент. Раньше добавлен, значит у него минимальный остаток ttl. Сложность o(1).

При неравномерном использовании и удалении самого малоиспользуемого все плохо. Нам надо в момент любого добавления знать какой элемент должен пойти на удаление. Заводим рядом TreeMap с объектами вида (id, количество обращений) и и компаратором по количеству обращений. Обновляем его одновременно с обновлением основного hashmap. Сложность вставки сильно возрастает o(logn). Сложность удаления o(1).

При массовых вставках и редких ситуациях переполнения по памяти можно сделать совсем просто: При достижении лимита сортируем исходный hashmap и удаляем самый малоиспользуемый. Долго при переполнении, зато вставку не замедляем и гарантируем не переполнение памяти. В сценарии редкого переполнения должно работать неплохо.
Допущения без которых никуда:
Требования по памяти приблизительные. Контролировать хотим, но небольшие отклонения не критичны.
Объем кеша такой что проход очистки по ttl по всем элементам занимает небольшое, по сравнению и с ttl и со временем когда кеш переполнится, время.

Тут надо уточнять насколько равномерно используются элементы кеша.
Предположим что очень неравномерно. К одному элементу единицы обращений за время жизни, ко второму тысячи. Соответственно мы хотим хранить активно используемые элементы до ttl, остальные можно выкидывать по памяти.
Добавляем в объект хранимый в кеше счетчик обращений. В функцию чистящую по ttl добавляем проверку на максимальный объем и при подходе к нему или превышении чистим самые неиспользуемые объекты. Так чтобы осталось процентов 80 (или сколько хотим) от максимально возможного. Поиск самых неиспользуемых и удаление тривиальны. По ресурсам или память для хранения и удаление при том же проходе. Или вообще без затрат: При первом проходе только ищем граничный по обращениям и при следующем цикле проверки ttl заодно удаляем все что ниже него. Память будет немного плавать, но сильного превышения не будет.

При равномерном обращении все аналогично только критерий удаления по памяти это время оставшееся до ttl. Других критериев у нас нет. При проходе очистки ищем граничный и при следующем удаляем все что ниже него.
Чувствуется опыт проведения собеседований. Во многих компаниях интервьюеры на быструю адаптацию вопросов не способны.

А что не так с самым простым ответом про кеш?
Язык Java.
Используем стандартный потокобезопасный ConcurrentHashMap. Получаем достаточно быстрое добавление. Добавление будет на порядок быстрее чем получение информации о статусе объекта. Поиск информации об объекте и получение будет просто быстрее некуда. TTL обрабатываем неторопясь отдельным потоком или потоками. Тоже самым стандартным способом hashMap.foreach(...). Возможны небольшие нарушения TTL, но такое обычно не критично. Если критично подгоняем TTL. Так чтобы время обработки всей коллекции + наш поправленный TTL были равны требуемому TTL.
Это проблема России, а не МКС. У нас даже с информированием плохо.
Летит Прогресс. Вода, еда, аппаратура починить МКС. О научной нагрузке информации около нуля.
Летит Драгон. Штука для эксперимента такого, штука для эксперимента этакого. Регулярные отчеты с самой МКС какие эксперименты проведены.

Кто нашим мешает так же отчитываться непонятно.
Ну это смотря сколько заплатят и кто попросит.
Придут вояки с очередной Зумой и мешком денег. Только очень тяжелой Зумой, так что с посадкой никак. И все запустят в одноразовом варианте на новой ракете.
А почему нет? Если покупатель оплачивать готов.
А зачем Маску понижать цену дальше? Он и так захватил весь рынок. Деньги на разработку BRF, на Старлинк, да даже на колонизацию Марсу нужны.

Для заказчика хотящего купить 100 запусков BFR оптом цены будут совсем другими.
Такое даже в банк клиентах не используется, насколько я в курсе.
2fa и хватит.

Не поделитесь где такое видели в реальной жизни?
Проверка прав доступа это просто пример. Самый очевидный, но пример.
Никто не мешает так валидировать обычные параметры. Когда по каким-то соображениям передается не объект, а пачка переменных.

Там какой-нибудь: /edit/setExternalLinkTo/anotherEntityId
Возвращать 400 нехорошо, а проверить существование сущности перед началом обновления объектов хочется.
Java EE вообще оказалась неудачной концепцией. JSR гораздо удобнее.

Ну тоже вариант. Мне ближе вариант все что можно повесить на аннотации и по максимуму задействовать функционал уже подключенных библиотек. Иногда это требует доработки напильником. Порог входа повышается, зато мест где можно сделать трудноуловимые ошибки становится гораздо меньше. Хотя и ловить их временами сложнее.
Получения объекта из хранилища это настолько типовая и дублирующаяся в куче мест операция что о ней можно не беспокоиться. Она должна работать, проверяться тестами и кешироваться. Правки затрагивающие ее не должны ломать существующий код.

Все остальное только в одном месте. Отдельно проверка прав доступа. Отдельно работа с объектом.

Новый человек должен быть в курсе таких вещей.
Меня и так в сложности решения чуть ниже упрекают. Хотя я и упрощал как мог.
Захотелось на русском написать. А кроме Хабра некуда.
Вы мало проектов на Спринге видели. @Validated это понятнее некуда. Самое простое и элегантное решение. Проверка в каждом методе и создание сообщений об ошибках во вью тоже в каждом методе, выходит в конечном итоге сложнее и потенциально содержит больше ошибок.

И обвязка это самое простое из того что я нашел в залежах «нестандартного Спринга». Все остальное там гораздо сложнее. Проблемы вида совместить windows domain sso и spring form authorization и заставить все это работать работать на виндовом кластере решаются гораздо сложнее. Там такие дебри…
С методами findByUsernameAndId(username, id) проверяюшими права возникает проблема когда надо делать доступ без пользователей. К примеру, автоматические выгрузки и тому подобные сервисные операции.

Приходится или разрешать username==null и давать доступ ко всему, что черевато дырами при ошибках в контроллерах.
Или заводить технические учетные записи, что вызывает проблемы управления и поддержки.
Или писать рядом такие же методы, не проверяющие права. Плохо само по себе.

Вариант findById(id) не проверяющее никаких прав и проверка прав на уровне контроллеров выглядит гораздо лучше.
Кеширование в помощь.
Второе обращение к документу не будет стоить практически ничего, по сравнению с первым.
В смысле зачем? Сценарий с доступом пользователя не ко всем сущностям одного типа очень стандартный.
От документооборотов (не все документы доступны) до форумов (не все разделы доступны) везде встречается.

Разрулить это спринговыми ролями невозможно. Доступ к методу у пользователя должен быть.

Бизнес логика это действия чтобы собрать и отдать этот объект. Неправильно в ней писать проверку прав пользователя.

Information

Rating
702-nd
Location
Москва и Московская обл., Россия
Date of birth
Registered
Activity