Re: Практическая задачка для профи по архитектуре
От: GlebZ Россия  
Дата: 19.07.07 15:09
Оценка: 21 (4)
Здравствуйте, Gangsta, Вы писали:

G>Чтобы было понятнее, приведу пример. Рассмотрим действие "коммент".


G>- запретить (Deny) "коммент" всем пользователям, у которых карма ниже -10

G>- обязательно спрашивать капчу (Captcha), если предыдущий коммент был менее 15 секунд назад
G>- всегда спрашивать капчу, если карма ниже 50
Немного перепишу сценарий:
Основной успешный сценарий:
1. Пользователь инициирует команду "коммент".
2. Система получает контекст пользователя.
3. Система проверяет что пользователь не обладает правами суперпользователя(если я правильно понял allow)
4. Система проверяет что у пользователя карма не ниже -10
5. Система проверяет что пользователь не производил команду "коммент" менее 15 секунд назад.
6. Система проверяет что карма не ниже 50
7. Система выполняет команду "коммент"
8. Система регистрирует в контексте пользователя о том, что прошла команда коммент.
9. Результат возвращается пользователю.
Альтернативные сценарии:
3.1 Пользователь обладает правами суперпользователя
3.2 Переход на пункт 7.

4.1 У пользователя карма меньше -10
4.2 Пользователь показывается окно с сообщением "??????"
4.3 Сценарий окончен

5.1 Пользователь производил комманду "коммент" менее 15 секунд назад.
5.2 Запускается сценарий "дай мне капчу"
5.3 Сценарий продолжается начиная с пункта 7

6.1 У пользователя карма менее 50 пунктов
6.2 Запускается сценарий "дай мне капчу"
6.3 Сценарий продолжается начиная с пункта 7

7.1 Выполнение дало ошибку
7.2 Сам думай как учитывать ситуацию

В таком виде уже более понятно.


G>Причем, ограничение может трассироваться по двум параметрам:

G>- по логину
G>- по айпишнику
И????

G>Другими словами, действие "регистрация" должно ограничиваться с учетом IP адреса. Т.е. не может быть больше 5 регистраций в 10 минут с одного IP.

Не очень хорошее действо учитывая то, что запрещая IP для одного человека, ты можешь запретить подсеть какой либо из компаний.(ходят то они через один IP) Эта система работает на RSDN для анонимов но не для тех кто залогинился..
Но по любому из действий надо строить свой полноценный сценарий.


G>Как это должно выглядеть в коде:

Почему именно так? Лучше разделить для каждого действия.


public void МуPage.Comment(...)
{
   UserContext context=UserContext.GetContext(session);
   VerifierResult result=CommentVerificator.CheckAction(context);
   switch (result.Error)
   {
       case EnumErrorResult.Capcha:
            Capcha.Check(context, page);
            break;
       case EnumErrorResult.Failed:
            Response.Redirect("error.aspx?error="+result.Message);
            break;
    }
    Actions.Comment(context, page, ....);
    CommentVerificator.UpdateUserContext(context);
}

//по мере(при) реализации сценариев, некоторые действия могут быть расширены и объеденены.
//учитываю только описанный сценарий.
public static VerifierResult CommentVerificator.CheckAction(UserContext context)
{
       if (UserContextHelper.IsAllowedAction(context, ActionEnum.Comment))
           return new VerifierResult(EnumErrorResult.OK);
       DateTime currentDateTime=DateTime.Now;
       Action action=UserContextHelper.GetLastAction(context, ActionEnum.Comment);
       if (action.Time.AddSecond(15)>currentDateTime)
          return new VerifierResult(EnumErrorResult.Capcha);
       Carma carma=UserContextHelper.GetCarma(context);
       if (carma.Value<=-10)
          return new VerifierResult(EnumErrorResult.Error, Resources.NoCarmaForContext);
       if (carma.Value<=50)
          return new VerifierResult(EnumErrorResult.Capcha);
       return new VerifierResult(EnumErrorResult.OK);
}

public static void CommentVerificator.UpdateUserContext(UserContext context)
{
       UserContextHelper.AddAction(new Action(ActionEnum.Comment, DateTime.Now, ...);
}

public class UserContext
{
   //кто-то из них может быть null
   IPAddress _ip;
   string _username;
   .........
}


Ничего сложного И согласно сценарию.


G>Особой остроты ощущений добавляет обязательное наличие следующей функциональности: необходимо ограничивать какие-то действия по их количеству за промежуток времени.


G>Например, разрешить (Allow) три поста подряд с любым интервалом, но потом спрашивать капчу (Captcha)

G>или
G>Разрешить (Captcha) три поста подряд, а потом запретить в течение какого-то времени действие "пост" (так сделано в reddit.com)
G>или
G>Разрешить (Captcha) три коммента за 5 минут, с любым интервалом
Это не вопрос архитектуры. Это вопрос постановки. Напиши набор сценариев, и все встанет на свои места. Представь себя не архитектором(и тем более не программистом) а аналитиком. Забудь про код и про архитектуру.
Re[6]: Практическая задачка для профи по архитектуре
От: Mikhail Polykovsky Россия http://glader.ru
Дата: 20.07.07 12:57
Оценка: 3 (1)
MP>>Борьба с ботами, маскирующимися под людей

IT>Замаскироваться под людей — это практически повторить функциональность браузера, при этом ориентироваться только на видимые контролы и ничего не знать о структуре документа.


Имеется в виду немного другое. Приходят пользователи, пишут немного комментов, и становится понятно, что не люди это, а какие-то боты. И вот карма+вменяемые пользователи помогают их отсечь.
Re: Практическая задачка для профи по архитектуре
От: Maxim S. Shatskih Россия  
Дата: 25.07.07 20:06
Оценка: 3 (1)
Как я понимаю, это типичная задача на aspect-oriented programming.

Так как решить надо на готовом и не aspect-oriented языке — можно сделать по классу для запроса капчи и для принятия решений о безопасности, и воткнуть обращения к ним повсеместно.

При необходимости смены алгоритмов можно эти классы переделать, не трогая все остальное.

К классу, проверяющему права и привилегии, идут постоянные обращения при каждом действии юзера. Потому завести там еще и временную метку последнего обращения — дело плевое.
Занимайтесь LoveCraftом, а не WarCraftом!
Re: Практическая задачка для профи по архитектуре
От: IT Россия linq2db.com
Дата: 19.07.07 15:43
Оценка: +1
Здравствуйте, Gangsta, Вы писали:

G>Ограничение может быть нескольких типов:

G>- Allow (т.е. нет ограничения, разрешить)
G>- Deny(reason) (запретить, одновременно указав причину запрета какого-либо действия [например, "ваша карма ниже нуля"])
G>- Captcha (обязательно требовать ввод кода с картинки)
G>- что-нибудь еще

Сразу бросается в глаза тот факт, что в одну кучу смешаны разные требования и как следствие будет смешана и реализация. Ограничение доступа к контенту и борьба с ботами — это абсолютно две разные задачи и решать их надо раздельно.
Если нам не помогут, то мы тоже никого не пощадим.
Re[9]: Практическая задачка для профи по архитектуре
От: IT Россия linq2db.com
Дата: 21.07.07 04:58
Оценка: :)
Здравствуйте, Mikhail Polykovsky, Вы писали:

MP>А при формулировке "защищаемся от плохих постов" получается вполне себе одна конструкция. Которую непонятно зачем растаскивать по разным местам.

А если это всё объеденить в "пишем сайт", то вообще будет ништяк
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Практическая задачка для профи по архитектуре
От: Gangsta  
Дата: 19.07.07 13:34
Оценка:
Вот вам практическая задачка из реальной жизни. Мой мозг пока не нашел простого решения.

Пишу проект на ASP.NET (2.0, C#). Есть сайт, на этом сайте пользователи могут оставлять посты, комментировать, голосовать и т.д. Для большинства возможностей необходима регистрация на сайте. Т.е. существуют некоторые действия:

— пост
— коммент
— голосование
— регистрация
(может быть что-нибудь еще — это я к тому, что архитектура должна быть легко расширяемой)

на все эти действия нужно наложить определенные ограничения. Ограничивать надо для того, что поддерживать _порядок_. Все ограничения зависят от каких-либо факторов. У пользователей, например есть такой параметр как _карма_. В зависимости от различных параметров, необходимо ограничивать пользователей в каких-либо действиях.

Ограничение может быть нескольких типов:
— Allow (т.е. нет ограничения, разрешить)
— Deny(reason) (запретить, одновременно указав причину запрета какого-либо действия [например, "ваша карма ниже нуля"])
— Captcha (обязательно требовать ввод кода с картинки)
— что-нибудь еще

Чтобы было понятнее, приведу пример. Рассмотрим действие "коммент".

— запретить (Deny) "коммент" всем пользователям, у которых карма ниже -10
— обязательно спрашивать капчу (Captcha), если предыдущий коммент был менее 15 секунд назад
— всегда спрашивать капчу, если карма ниже 50

Причем, ограничение может трассироваться по двум параметрам:
— по логину
— по айпишнику

Другими словами, действие "регистрация" должно ограничиваться с учетом IP адреса. Т.е. не может быть больше 5 регистраций в 10 минут с одного IP.

Как это должно выглядеть в коде:

UserContext userContext = getContext(); // получаем логин, IP пользователя, карму и другие параметры
Verifier verifier = getVerifier();
VerifierResult result = verifier.CheckAction(ActionType.Comment, userContext);

if(VerifierResult.Allow == result)
{
// добавить комментарий
}
else if(VerifierResult.Deny == result) {
// вывести сообщение об ошибке
}
else if(VerifierResult.Captcha == result)
{
// спросить капчу (конечно, это лучше делать в Page_Load, чтобы сразу спрашивать, если что)
}


Особой остроты ощущений добавляет обязательное наличие следующей функциональности: необходимо ограничивать какие-то действия по их количеству за промежуток времени.

Например, разрешить (Allow) три поста подряд с любым интервалом, но потом спрашивать капчу (Captcha)
или
Разрешить (Captcha) три поста подряд, а потом запретить в течение какого-то времени действие "пост" (так сделано в reddit.com)
или
Разрешить (Captcha) три коммента за 5 минут, с любым интервалом

Вот такая задачка. Только не говорите, что функционал лишний. Хотелось бы комментариев по поводу того, как сделать то, что описано выше (а не комментариев в стиле "мне кажется, что ты заморачиваешься, достаточно одной проверки" или "все люди делают по-другому").
Re: Практическая задачка для профи по архитектуре
От: Нахлобуч Великобритания https://hglabhq.com
Дата: 19.07.07 14:35
Оценка:
Здравствуйте, Gangsta, Вы писали:

G>Вот такая задачка. Только не говорите, что функционал лишний. Хотелось бы комментариев по поводу того, как сделать то, что описано выше (а не комментариев в стиле "мне кажется, что ты заморачиваешься, достаточно одной проверки" или "все люди делают по-другому").


ИМХО.

Вы сразу замахиваетесь на создание слишком сложной системы. Сложные системы сразу не делаются -- они получаются из простых. В вашем же случае вы рискуете огрести по полной как на Emergent behaviour, так и на общем взаимодействии всего вашего хозяйства.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
HgLab: Mercurial Server and Repository Management for Windows
Re[2]: Практическая задачка для профи по архитектуре
От: Gangsta  
Дата: 19.07.07 15:46
Оценка:
Здравствуйте, Нахлобуч, Вы писали:

Н>Вы сразу замахиваетесь на создание слишком сложной системы. Сложные системы сразу не делаются -- они получаются из простых. В вашем же случае вы рискуете огрести по полной как на Emergent behaviour, так и на общем взаимодействии всего вашего хозяйства.


Общее взаимодействие как раз получается простым. Что может быть проще -- подключаем отдельный проект (project) к существующему решению (solution) и в основном проекте пишем проверку (в тех местах, где нужно) на Allow, Deny или Captcha. Вся остальная логика — в отдельном проекте. Поэтому общее взаимодействие не страдает. Ничто не мешает написать нам DummyVerifier, который всегда будет выдавать Allow. И код основного проекта не поменяется. Так что насчет общего взаимодействия всего хозяйства вы погорячились.

Я тут кое-что налабал, рабочий код получается примерно следующий:


            DefaultRuleResolver rr = new DefaultRuleResolver(new BannedModificator());
            Action.Action action = new ActionController.Action.Action(ActionType.Comment, TrackMode.IP, DateTime.Now.AddDays(-100));
            Context context = new Context("aa", "127.0.0.1", -10);

            RuleResult result = rr.Resolve(action, context);
            Console.WriteLine(result.ToString());
            Console.WriteLine("Error: '" + rr.LastError + "'");


Код полностью тут: http://webfile.ru/1473457
можно поиграться (поставьте там с dll на exe, а то забыл).

Вопрос возникает в том, как сделать это грамотно. А именно — запоминание действий пользователя. Ведь особой сложности остальное не представляет. Где и как лучше запоминать действия пользователя?

Есть идея создать отдельный класс, держать его в сессии. Если пользователь совершил действие, мы делаем что-то типа:

userContext.IncreaseCommentCounter();
или
userContext.IncreasePostCounter();

И потом на основе этого контекста принимать решение. Естественно, что класс должен как-то сериализоваться или чтобы была возможность его инициировать.

Просто может быть кто-нибудь сообразит как сделать проще?
Re[2]: Практическая задачка для профи по архитектуре
От: Gangsta  
Дата: 19.07.07 15:54
Оценка:
Здравствуйте, IT, Вы писали:

IT>Сразу бросается в глаза тот факт, что в одну кучу смешаны разные требования и как следствие будет смешана и реализация. Ограничение доступа к контенту и борьба с ботами — это абсолютно две разные задачи и решать их надо раздельно.


А где ограничение доступа к контенту? Все могут смотреть все. Если есть где-то ограничение доступа, то это на уровне ASP.NET, аутентификация, авторизация и т.д. Поэтому тут задача одна — борьба с ботами.
Re[3]: Практическая задачка для профи по архитектуре
От: IT Россия linq2db.com
Дата: 19.07.07 15:58
Оценка:
Здравствуйте, Gangsta, Вы писали:

G>А где ограничение доступа к контенту? Все могут смотреть все. Если есть где-то ограничение доступа, то это на уровне ASP.NET, аутентификация, авторизация и т.д.


К сожалению, на ASP.NET далеко не уедешь.

G>Поэтому тут задача одна — борьба с ботами.


А что тогда такое карма?
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: Практическая задачка для профи по архитектуре
От: Mikhail Polykovsky Россия http://glader.ru
Дата: 20.07.07 12:00
Оценка:
G>>Поэтому тут задача одна — борьба с ботами.

IT>А что тогда такое карма?


Борьба с ботами, маскирующимися под людей
Re[5]: Практическая задачка для профи по архитектуре
От: IT Россия linq2db.com
Дата: 20.07.07 12:37
Оценка:
Здравствуйте, Mikhail Polykovsky, Вы писали:

MP>Борьба с ботами, маскирующимися под людей


Замаскироваться под людей — это практически повторить функциональность браузера, при этом ориентироваться только на видимые контролы и ничего не знать о структуре документа.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re: Практическая задачка для профи по архитектуре
От: BulatZiganshin  
Дата: 20.07.07 14:16
Оценка:
Здравствуйте, Gangsta, Вы писали:

G>Вот вам практическая задачка из реальной жизни. Мой мозг пока не нашел простого решения.


что сделано у мня в одной из прогшрамм — есть модуль, которому передают текстовую строку, и он по ней возвращает уровень доступа — none/read/rw. в твоём случае этому же модулю должны отчитываться о всей сетевой активности пользователя другие модули. тут хорошо бы подошла архитектура с шиной сообщений — посмотри сам, будет ли это полезно для реализации остальных фич в программе. как вариант — сделать спецмодуль для логгирования вех действий пользователей, и запрашивать необходимую для первого модуля информацию у него

архитектура в общем-то зависит от того, что с чем ты хочешь объединить. если тебе удобно в каждом действии, представляемом своим объектом, иметь свой собственный метод проверки на разрешение операции — это одно, тогда тебе нужен только модуль статистики/состояни, который сообает нужную информацию о пользователе и его активности. если все проверки однотипны — то для них удобно завести отдлельный модуль/объект и передавать ему сроку, как у меня. если нечто комбинированное — надо сделать набор высоковровневых правил проверки и писать в каждом действии код на пару строк, которые комбинирует их в нужном сочетании. ну а если ты этого заранее не знаешь, то тебя ждёт жопа рефакторинга
Люди, я люблю вас! Будьте бдительны!!!
Re[7]: Практическая задачка для профи по архитектуре
От: IT Россия linq2db.com
Дата: 20.07.07 23:22
Оценка:
Здравствуйте, Mikhail Polykovsky, Вы писали:

IT>>Замаскироваться под людей — это практически повторить функциональность браузера, при этом ориентироваться только на видимые контролы и ничего не знать о структуре документа.


MP>Имеется в виду немного другое. Приходят пользователи, пишут немного комментов, и становится понятно, что не люди это, а какие-то боты. И вот карма+вменяемые пользователи помогают их отсечь.


Т.е. защищаемся всё же от людей. Ну так это тоже совсем другая функциональность, которую нужно решать отдельно, а не мешать всё в кучу.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: Практическая задачка для профи по архитектуре
От: Mikhail Polykovsky Россия http://glader.ru
Дата: 21.07.07 03:31
Оценка:
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, Mikhail Polykovsky, Вы писали:


IT>>>Замаскироваться под людей — это практически повторить функциональность браузера, при этом ориентироваться только на видимые контролы и ничего не знать о структуре документа.


MP>>Имеется в виду немного другое. Приходят пользователи, пишут немного комментов, и становится понятно, что не люди это, а какие-то боты. И вот карма+вменяемые пользователи помогают их отсечь.


IT>Т.е. защищаемся всё же от людей. Ну так это тоже совсем другая функциональность, которую нужно решать отдельно, а не мешать всё в кучу.


А при формулировке "защищаемся от плохих постов" получается вполне себе одна конструкция. Которую непонятно зачем растаскивать по разным местам.
Re[10]: Практическая задачка для профи по архитектуре
От: Mikhail Polykovsky Россия http://glader.ru
Дата: 21.07.07 08:39
Оценка:
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, Mikhail Polykovsky, Вы писали:


MP>>А при формулировке "защищаемся от плохих постов" получается вполне себе одна конструкция. Которую непонятно зачем растаскивать по разным местам.

IT>А если это всё объеденить в "пишем сайт", то вообще будет ништяк

Ну это уж ты загнул Здесь играет роль чувство баланса. А поскольку у всех оно разное, особо спорить об архитектуре сложно.
Re: Практическая задачка для профи по архитектуре
От: awhiler  
Дата: 22.07.07 17:53
Оценка:
http://msdn2.microsoft.com/en-us/library/bb410105.aspx
Re[7]: Практическая задачка для профи по архитектуре
От: Maxim S. Shatskih Россия  
Дата: 23.07.07 19:14
Оценка:
MP>Имеется в виду немного другое. Приходят пользователи, пишут немного комментов, и становится понятно, что не люди это, а какие-то боты. И вот карма+вменяемые пользователи помогают их отсечь.

Да неверно.

Карма нужна для выстраивания социальных иерархий на ресурсе, а не для борьбы с ботами.

Карма приводит к тому, что на ресурсе остаются более или менее единомышленники по всем важным вопросам, а те, кто мыслит иначе, чем эта тусовка — планомерно выжимаются.

Потому запрашивать капчу потому, что карма низка — похоже на бред.

В ЖЖ капча запрашивается только для анонимок.
Занимайтесь LoveCraftом, а не WarCraftом!
Re[8]: Практическая задачка для профи по архитектуре
От: Mikhail Polykovsky Россия http://glader.ru
Дата: 24.07.07 04:15
Оценка:
Здравствуйте, Maxim S. Shatskih, Вы писали:

MP>>Имеется в виду немного другое. Приходят пользователи, пишут немного комментов, и становится понятно, что не люди это, а какие-то боты. И вот карма+вменяемые пользователи помогают их отсечь.


MSS>Да неверно.


MSS>Карма нужна для выстраивания социальных иерархий на ресурсе, а не для борьбы с ботами.


Ты знаешь, я наблюдал разные применения кармы. Для борьбы с "ботами" она тоже подходитю
Re[8]: Практическая задачка для профи по архитектуре
От: Gangsta  
Дата: 24.07.07 10:24
Оценка:
Здравствуйте, Maxim S. Shatskih, Вы писали:

MSS>Потому запрашивать капчу потому, что карма низка — похоже на бред.


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

А представь себе ситуацию когда есть новый аккаунт, написан специальный софт, который каждый день добавляет в разные темы комменты в автоматическом режиме. Лояльные пользователи не пройдут мимо трэша, поставят минус. Если не будет капчи, то минус никакой роли не сыграет. И отрицательная карма в этом случае важна как индикатор того, что к данному пользователю на данный момент нет доверия.
Re: Практическая задачка для профи по архитектуре
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 26.07.07 09:11
Оценка:
Здравствуйте, Gangsta, Вы писали:

G>Вот такая задачка. Только не говорите, что функционал лишний. Хотелось бы комментариев по поводу того, как сделать то, что описано выше (а не комментариев в стиле "мне кажется, что ты заморачиваешься, достаточно одной проверки" или "все люди делают по-другому").


С учетом поста
Автор: GlebZ
Дата: 19.07.07
Глеба рекомендую Вам поступить так:

1. Составить полный перечень операций (на макроуровне), которые должна выполнить система в ответ на действие пользователя по добавлению комментария.

По всей видимости, получится что-то типа этого:

1) Получить комментарий и контекст пользователя.
2) Запросить и получить капчу.
3) Поместить комментарий в базу данных.
4) Вывести сообщение (о том, что комментарий добавлен или, наоборот, не добавлен).

2. Для каждого из этих действий создать по модулю (классу), который действует автономно. У Вас получатся:


Обратите внимание, что это только первичные абстракции. По ходу анализа они могут изменяться и уточняться.

3. Организовать обработку сообщения от пользователя в виде конвеера — когда каждое полученное сообщение проходит последовательно все эти четыре этапа.

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

Понятно, что коммуникация между этими модулями производится на асинхронной основе.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.