Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];

Вниз

Вход в программу 1 раз под 1 пользователем   Найти похожие ветки 

 
И. Павел ©   (2012-03-19 11:19) [0]

Здравствуйте.

Нужно запретить вход пользователю «A» в программу, если с другого или того же самого компьютера этот пользователь уже вошел (и еще не вышел). Уже обдумывал решение этой задачи, и даже на форуме спрашивал, но к окончательному решению тогда так и не пришел.

Проверять — зашел ли в MS SQL определенный пользователь не получится, т.к. все пользователи программы заходят в MS SQL под одним логином.
Если просто при входе и выходе пользователя «A» ставить метку где-то в БД, то может оказаться, что пользователь «A» просто нажал reset и не может войти в программу, т.к. она считает, что он все еще из нее не вышел.  

Сейчас у меня есть такой вариант решения:
При входе пользователя &laquo;A&raquo;, в какую-нибудь таблицу, в запись, соответствующую этому пользователю, в поле LastPresence пишется время его входа и каждые 5 минут программа, в которой работает пользователь, посылает запросы, записывая в это поле текущее время. При выходе пользователя в поле lastpresence можно писать маленькую дату, например 1900 год. При очередном входе пользователя &laquo;A&raquo; проверяется: если <текущее время> &#151; LastPresence > 10 мин, то входить можно. Но пользователей сейчас около тысячи, и такой метод нагрузит сервер (особенно если программа будет у многих работать в холостом режиме, свернутая на панели задач).

Порекомендуйте, пожалуйста, способ решения такой задачи.

Еще хочется избежать ситуации, когда с двух компьютеров одновременно войдет пользователь &laquo;A&raquo; (с одного компьютера &#151; &laquo;A1&raquo;, а с дрегого &#151; &laquo;A2&raquo;). Т.е.:
&#151; &laquo;A1&raquo; проверит, что никто не вошел.
&#151; Тут же &laquo;A2&raquo; проверит, что никто не вошел.
&#151; &laquo;A1&raquo; войдет и отметит, что он вошел.
&#151; &laquo;A2&raquo; войдет и отметит, что он вошел (затрет метку A1).

Т.е. хотелось бы иметь синхронную функцию на SQL SERVER, которая не может выполняться параллельно для нескольких пользователей. Имеется ли такая возможность? Если использовать блокировки записей, то может произойти эскалация (хотя учитывая небольшое время блокировки, наверное, это не может привести к длительным простоям, но все же хотелось бы использовать более удобный метод).

Заранее спасибо.


 
CRLF   (2012-03-19 11:32) [1]


> Заранее спасибо.
Не за что.


 
icelex ©   (2012-03-19 11:42) [2]

Используй подобие сессий. То, что ты описал очень похоже.
При входе пользователя создается запись в таблице типа UserId, SessionId, LastTime.
При выходе запись удаляется.
Раз в определенное время обновляешь LastTime.


 
Медвежонок Пятачок ©   (2012-03-19 11:47) [3]

все пользователи программы заходят в MS SQL под одним логином.

сначала сам придумал трудности и теперь сам их преодолеваешь.
почему не доменная аутентификация? гранты лень раздавать?


 
Inovet ©   (2012-03-19 11:52) [4]

> [2] icelex ©   (19.03.12 11:42)
> При выходе запись удаляется.

Зачем удалять? Хранить время входа, время последней активности, время выхода. Но проблему это не решает.


 
И. Павел ©   (2012-03-19 12:00) [5]

> [2] icelex ©   (19.03.12 11:42)

Большое спасибо. Кстати, только что дошло, что если сделать UserID уникальным индексом (и удалять старые UserID), то второй вопрос отпадет &#151; войти второму пользователю с тем же UserID до того, как первый пользователь успеет отметиться, не получится. В худшем случае MS SQL вернет ошибку.


> [3] Медвежонок Пятачок ©   (19.03.12 11:47)

Доменная аутонтефикация тоже накладывает свои ограничения. Например, если один пользователь работает с несколькими логинами по очереди. А учитывая то, что программа далеко вышла за пределы исходного ТЗ, уже сложно сказать, при выборе какого способа аутентификации было бы меньше сложностей при ее доработке.


 
И. Павел ©   (2012-03-19 12:02) [6]

> Зачем удалять?

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

Но недостаток метода остается: программы будут постоянно обращаться к MS SQL SERVER. А экземпляров программы много.


 
Inovet ©   (2012-03-19 12:12) [7]

> [6] И. Павел ©   (19.03.12 12:02)
> Да, можно не удалять, а включить в индекс второе поле (del)
> , чтобы отличать новые записи от старых.

У новых время входа будет меньше старых. Время выхода пустое + проверка времени последней активности на случай отваливания соединения - активный. 1000 активных раз в 10 минут обновляют - это около 1 запроса в секунду.

А что нет какого-то стандартного механизма для этого? Такой вопрос не первый раз вижу.


 
icelex ©   (2012-03-19 12:35) [8]


> Inovet ©   (19.03.12 11:52) [4]

а чё их хранить-то, такая цаца штоль? :)
если есть запись, значит проверяем время. Если текущее минус то время меньше интервала обновления, удаляем старую запись, создаем новую сессию, если нет - пользователь сисдит. Если нет записи, тоже долой.
Вот если логирование входа надо вести, то тогда другое дело.


 
NkzAlex ©   (2012-03-19 12:35) [9]

т.к. все пользователи программы заходят в MS SQL под одним логином

Интересное решение. Если не подходит Win аутентификация, то что мешает выдать SQL логин каждому пользователю?\

Кстати, только что дошло, что если сделать UserID уникальным индексом (и удалять старые UserID), то второй вопрос отпадет — войти второму пользователю с тем же UserID до того, как первый пользователь успеет отметиться, не получится.

При разрыве соединения, отличающегося от штатного, пользователь так и будет считаться авторизованным? И собственно зачем ограничивать пользователя единственным соединением?


 
Inovet ©   (2012-03-19 12:41) [10]

> [8] icelex ©   (19.03.12 12:35)
> Вот если логирование входа надо вести, то тогда другое дело.

Ну, так заодно и логировать, много есть не просит, а глядиь, и сгодится.


 
Inovet ©   (2012-03-19 12:42) [11]

> [9] NkzAlex ©   (19.03.12 12:35)
> И собственно зачем ограничивать пользователя единственным
> соединением?

Мне это тоже интересно.


 
TUser ©   (2012-03-19 13:15) [12]


> такой метод нагрузит сервер

как варант - проверять не каждые 5 минут, а при попытке логина отправлять запрос предыдущему залогиневшемуся пользователю А


 
И. Павел ©   (2012-03-19 13:33) [13]

> И собственно зачем ограничивать пользователя единственным
> соединением?

Хороший вопрос... Заказчик не вспомнил &#151; зачем ему это было нужно и задачу отменили. Как вспомнят &#151; опять вопрос тут подниму :)

PS: но если у кого-то есть предложения по тому, как решить такую задачу &#151; было бы интересно их узнать.


 
Ega23 ©   (2012-03-19 13:33) [14]


> Интересное решение.


Решение как решение. У тебя может быть своя собственная авторизация, к grant-revoke не имеющая никакого отношения.
Автору: механизм сессий, a-la тот же PHP.


 
И. Павел ©   (2012-03-19 13:35) [15]

> как варант &#151; проверять не каждые 5 минут, а при попытке
> логина отправлять запрос предыдущему залогиневшемуся пользователю
> А

Тогда придется еще и присоединять к пользователю &laquo;сервер&raquo;, а к серверу писать клиента для пользовательского сервера... И тоже слаюым местом системы является проблема со связью &#151; если пользователь не ответил, это еще не значит, что его нет.


 
Ega23 ©   (2012-03-19 13:51) [16]


> Тогда придется еще и присоединять к пользователю «сервер»,
>  а к серверу писать клиента для пользовательского сервера.
> .. И тоже слаюым местом системы является проблема со связью
> — если пользователь не ответил, это еще не значит, что его
> нет.


Ничего не надо.
Для SQL Server пишется job, который стартует каждые N промежутков времени.
В рамках сервера заводится 2 таблицы. Одна - ID пользователя, Login, password.
Вторая - ID пользователя, ID сессии (guid), время последнего действия.
При успешном вводе логина-пароля сканируем таблицу подключений на предмет данного UserID. если нет - записываем с текущим временем, возвращаем SID. Если есть - просто возвращаем SID.
На каждое действие пользователя обновляем таблицу подключений (время последнего действия).
В job-е смотрим, есть ли в таблице кто, у кого текущее время - время последнего действия >= N. Если есть - кикаем их КЕБМ.
как-то так.


 
Труп Васи Доброго ©   (2012-03-19 14:06) [17]

В чём проблема то? Вот в SAP R3 сделано так, если входит юзер с тем же логином, то ЕМУ сообщается что в данный момент активна другая сессия (показывается время входа) и задаётся вопрос войти под другим логином или "выкинуть" более раннюю сессию. Вот и всё. Если юзер должен быть один, то это один человек и он имеет право выгонять любого, кто шуршит под его логином. (сохранность логина проблема юзера, а не программиста) Так же завершаются и висящие сессии. Вообще то там при неактивности юзера его по любому через тайм-аут выкинет.


 
Ega23 ©   (2012-03-19 15:57) [18]


> В чём проблема то? Вот в SAP R3 сделано так, если входит
> юзер с тем же логином, то ЕМУ сообщается что в данный момент
> активна другая сессия (показывается время входа) и задаётся вопрос


Насколько я понял, вопрос был в том, как это реализовать.


 
Kerk ©   (2012-03-19 16:46) [19]

Блокируй какой-нибудь ресурс при входе. Например, строку с ID юзера в таблице юзеров. Тогда при попытке повторной блокировки будет ошибка. Если сессия отвалится, то ресурс освободится.


 
И. Павел ©   (2012-03-19 16:52) [20]

> [16] Ega23 ©   (19.03.12 13:51)

Спасибо, метод интересный.
Но тоже есть недостаток: пользователь может быть неактивен длительное время. Многие не закрывают, а просто сворачивают программу. Будет лишнее неудобство &#151; программа будет сообщать об устаревании сессии, к такой реакции от десктопных программ пользователи не привыкли.


> [19] Kerk ©   (19.03.12 16:46)

Я про это в [0] посте писал &#151; если возникнет эскалация, никто из 1000 пользователей не сможет войти в программу. А запретить эскалации в MS SQL SERVER, кажется, невозможно.


 
И. Павел ©   (2012-03-19 16:59) [21]

> [19] Kerk ©   (19.03.12 16:46)

Хотя насколько вероятна эскалация в таблице из 1000 записей, в которой блокировка идет по первичному ключу? Может быть, такого и быть не может? В документации я так ничего и не нашел по этому поводу.


 
Abra   (2012-03-19 17:07) [22]


> > В чём проблема то? Вот в SAP R3 сделано так, если входит
> > юзер с тем же логином, то ЕМУ сообщается что в данный
> момент
> > активна другая сессия (показывается время входа) и задаётся
> вопрос
>
>
> Насколько я понял, вопрос был в том, как это реализовать.
>

Таблица сессий, храним сессии-логины, при выходе очищаем строку
если юзер не вышел (вышел некорректно), следующий под таким же логином делает kill @PID

Syntax
KILL { session ID | UOW } [ WITH STATUSONLY ]

Arguments
session ID
Is the session ID of the process to terminate. session ID is a unique integer (int) that is assigned to each user connection when the connection is made. The session ID value is tied to the connection for the duration of the connection. When the connection ends, the integer value is released and can be reassigned to a new connection.

Use KILL session ID to terminate regular nondistributed and distributed transactions that are associated with a specified session ID.

UOW
Identifies the Unit of Work ID (UOW) of distributed transactions. UOW is a GUID that may be obtained from the request_owner_guid column of the sys.dm_tran_locks dynamic management view. UOW also can be obtained from the error log or through the MS DTC monitor. For more information about monitoring distributed transactions, see the MS DTC documentation.

Use KILL UOW to terminate orphaned distributed transactions. These transactions are not associated with any real session ID, but instead are associated artificially with session ID = "-2". This session ID makes it easier to identify orphaned transactions by querying the session ID column in sys.dm_tran_locks, sys.dm_exec_sessions, or sys.dm_exec_requests dynamic management views.

WITH STATUSONLY
Generates a progress report about a specified session ID or UOW that is being rolled back due to an earlier KILL statement. KILL WITH STATUSONLY does not terminate or roll back the session ID or UOW; the command only displays the current progress of the rollback.


 
Ega23 ©   (2012-03-19 17:15) [23]


> Но тоже есть недостаток: пользователь может быть неактивен
> длительное время. Многие не закрывают, а просто сворачивают
> программу. Будет лишнее неудобство — программа будет сообщать
> об устаревании сессии, к такой реакции от десктопных программ
> пользователи не привыкли.


Делай "рукопожатие".
Например. Ты запустил свою программу. Что-то ушло в БД. У тебя при этом запустился таймер (либо поток), который должен сработать через N времени. Если за этот N клиент проявил некую активность (что-то выбрал, что-то изменил, что-то удалил), то N начинает высчитываться по-новой. Ели товарищ ушёл курить, то твой таймер через N времени кричит серверу "Я жЫвой". Соответственно, тот продляет жизнь сессии.
Если время активности не сильно критично (минуты или десятки минут), то можно вообще не заморачиваться, тупо по таймеру слать LAM и дело с концом. Если счёт на десятки секунд - то да, надо тогда за активностью следить и таймер корректировать.
Время подбирать исходя из трёх критериев:
1. Время обработки самого здоровенного запроса (плюс нужно ещё процентов 50 добавить. Например.)
2. Пожелание заказчика.
3. Здравый смысл.


 
Ega23 ©   (2012-03-19 17:17) [24]


> Таблица сессий, храним сессии-логины, при выходе очищаем
> строку
> если юзер не вышел (вышел некорректно), следующий под таким
> же логином делает kill @PID


Я в программе могу пустить десяток тредов, каждый из которых будет иметь свой собственный коннект к БД, с шахматами и поэтессами. Но каждый из них будет идти под одним нашим логическим SID. С другой стороны, со стороны сервера каждый из них будет обладать своим PID.


 
Kerk ©   (2012-03-19 17:20) [25]


> Ega23 ©   (19.03.12 17:17) [24]

В SQL Server действительно принято направо и налево раздавать право убивать чужие сессии?


 
Abra   (2012-03-19 17:22) [26]

procedure KillByLogin
declare C cursor for select PID from where SID=
open C, fetch next PID into @PID, while @@fetch_status <> 0 kill @PID


 
Abra   (2012-03-19 17:24) [27]


> В SQL Server действительно принято направо и налево раздавать
> право убивать чужие сессии?

сам как думаешь? :)
но если программа от одного логина, она должна уметь многое, например, если админ зайдет, он же тоже зайдет под тем же логином, что и все..


 
Ega23 ©   (2012-03-19 17:24) [28]


> В SQL Server действительно принято направо и налево раздавать
> право убивать чужие сессии?


Нет, о чём я товарищу и хочу сказать.
Я убийством pid-ов занимался один-единственный раз: когда писал процедуру восстановления БД из нашей админки. И то, там предлагалось либо отключить всё штатно, либо убить принудительно.


 
Ega23 ©   (2012-03-19 17:38) [29]


> но если программа от одного логина, она должна уметь многое,
>  например, если админ зайдет, он же тоже зайдет под тем
> же логином, что и все..


Не путай логин-авторизацию на сервере и логин-авторизацию в рамках твоей программы.


 
Abra   (2012-03-19 17:44) [30]


> е путай логин-авторизацию на сервере и логин-авторизацию
> в рамках твоей программы.

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


 
Ega23 ©   (2012-03-19 17:46) [31]

И в догонку: для чего приложение ходит на сервер под одной серверной учётной записью. На первый взгляд - маразм, ибо та же windows-авторизация.
Но. У тебя могут быть гетерогенные запросы к данному серверу. От хрен знает кого, хоть из вражеского Линукса, или из другой СУБД. И тут уже ой.


 
Ega23 ©   (2012-03-19 17:50) [32]


>  итого пользователь на сервере, от имени которого работает
> программа, должен уметь и то, и другое.


да проходили это уже. Фактически, у тебя в программе есть некие "бизнес-действия". "Добавить категорию товара", "Распечатать накладную вида N", "Показать детальный лог действий пользователей" и т.п.
Данные бизнес-действия прикрутить к системе grant-revoke весьма проблематично. Да и некрасиво будет, если ты в программе жмёшь кнопку "распечатать", а она тебе исключение выкидывает. Данная кнопка должна быть задизейблена либо вообще не видна.
Отсюда и делается внутренняя авторизация, в рамках логики твоей программы. И тут уже в целом пофиг, под какой учёткой они ходят на сервер.


 
Abra   (2012-03-19 17:55) [33]


> Фактически, у тебя в программе есть некие "бизнес-действия".
>  "Добавить категорию товара", "Распечатать накладную вида
> N", "Показать детальный лог действий пользователей" и т.
> п.

вот именно!
а поэтому реальная авторизация - это права на все это.
Внутренняя может не дать одно, второе, третье - но реальный пользователь (фактически, единственный, от кого программа и коннектится изначально)имеет права на это все.  Что же такого плохого, если он сможет еще и PID прибить


 
NKZAlex ©   (2012-03-19 18:48) [34]

У нас работал такой вариант, правда каждый пользователь имел свою sql учетку, либо win.  Пользователь входит,  в таблицу записывается информация однозначно идентифицирующая пользователя в рамках системы,
например: логин/пароль. Если кто-то пытается авторизоваться с теме же параметрами, простейшая проверка, выдается сообщение об ошибке. При выходе из программы запись из таблицы удаляется, ес-но еще лог ведется и т.д. Параллельно работает job, который проверяет соответствие записи в таблице авторизации реально  открытому соединению, если соединения нет запись из таблицы удаляется. Пока программа клиента не разрывает соединение, повторно залогиниться нельзя.


 
Ega23 ©   (2012-03-19 19:14) [35]


> а поэтому реальная авторизация - это права на все это.


Ещё раз. Реальная авторизация нужна для раздачи прав на "владение" разными объектами БД, а также на действия, совершаемые с этой БД.
Права на backup базы. Права на restore базы. Права на создание таблицы/вьюхи/хп/схемы. Права на чтение данных из таблицы/вьюхи. Права на изменение данных. Права на запуск хп. И т.д.
К "бизнес-действиям" в твоём ПО это вообще никак не относится. Оно может иметь устойчивую корреляцию, но совершенно не обязано её иметь.
А убивать процессы.. Ну с одной стороны никто не запрещает. С другой проблем на этом поиметь можно - мильён. ИМХО, фиговая архитектура системы.


 
Ega23 ©   (2012-03-19 19:21) [36]


>  Параллельно работает job, который проверяет соответствие
> записи в таблице авторизации реально  открытому соединению


Сервера под рукой нет, чтобы проверить. Но что-то такое, связанное с реализацией MSSQL-ного пула соединений было.
Ну, типа, есть приложение, которое создаёт соединение, что-то быстро делает и штатно его рвёт. И так в бесконечном цикле. Запускаем десяток таких программ. И не наблюдаем лавинообразного роста значений PID на сервере.
С проблемой сталкивался лет 6 назад, тогда же тут это дело в обсуждении проскакивало.
В общем, подробностей не помню, но данный вариант лично мне также не представляется надёжным.

Ну и эта, народ. Смотрите в сторону web-сессий, всё уже придумано до нас, нафига велосипед изобретать? У нас даже преимущество в виде постоянного коннекта.


 
картман ©   (2012-03-19 22:03) [37]

http://msdn.microsoft.com/ru-ru/library/bb326598.aspx


 
знайка   (2012-03-19 23:34) [38]


> Смотрите в сторону web-сессий, всё уже придумано до нас
сессии как-бы не для этого придуманы, и они не запрещают мульти-логонов.

Собственно, как и инекоторые здесь так и не понял, в чем смысл запрета...


 
NkzAlex ©   (2012-03-20 06:23) [39]

В общем, подробностей не помню, но данный вариант лично мне также не представляется надёжным.

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



Страницы: 1 вся ветка

Форум: "Прочее";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.58 MB
Время: 0.06 c
1-1294927466
VLK32
2011-01-13 17:04
2013.03.22
Использование generics для реализации двойной сортировки


11-1242650049
QAZ
2009-05-18 16:34
2013.03.22
TreeView + Checkbox


15-1346212466
Al2017
2012-08-29 07:54
2013.03.22
Не выходит задать течение нескольких несвязанных труб


2-1332165801
Валера
2012-03-19 18:03
2013.03.22
Не компилируется проект с компонентом RS232


1-1298375588
юрий_карлик
2011-02-22 14:53
2013.03.22
компонент TChart, как скрыть конкретные точки в графике





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский