воскресенье, 10 июня 2012 г.

Управляем доступом - 1. Аутентификация.

Я не забросил блог, я просто немного отдыхал ;)



Следующие два (или три?) поста будут посвящены системе управления доступом, которая используется в моем проекте. Под "управлением доступом" я буду подразумевать в данном случае аутентификацию пользователей и систему раздачи прав на какие-либо действия и интерфейсные элементы.

Способы аутентификации в апексе

Самый простой способ - это аутентификация пользователей БД или APEX. Это две возможные схемы, которые есть в апексе по умолчанию. В первом случае вы управляете доступом с помощью средств самой СУБД, которая знать не знает ничего ни о каком апексе, потому что апекс - это всего лишь некая внешняя надстройка, пусть даже и тесно интегрированная с БД. Во втором случае вы даете доступ людям, которые зарегистрированы как пользователи или разработчики APEX. Их список вы можете увидеть в разделе Administration - > Manage Users and Groups. Эти две схемы удобны для внутренней корпоративной сети, но как только вы впервые переезжаете на хостинг с ограничением количества пользователей (БД или апекса), вы тут же становитесь одним из желающих прочесть этот пост ;). Специально для таких случаев (когда или проще нельзя, или хочется странного) есть возможность создать кастомную схему аутентификации.

Кастомная схема

Для кастомной схемы нужно создать таблицу, в которой мы будем хранить список пользователей. В простейшем случае - пары "логин - пароль", остальную информацию (имена, телефоны, адреса, даты рождений и прочий хлам) вы вполне сможете запихать туда без моей помощи в случае необходимости. Пусть, например, наша таблица называется USERS и состоит из полей ID, LOGIN и PWD.

Саму схему можно создать в разделе Shared Components -> Authentication Schemes:
  • нажимаем кнопочку Create;
  • выбираем способ создания - From Scratch (то есть "с нуля");
  • задаем имя для схемы;
  • затем можно ввести текст Page Sentry Function - это функция, которая выполняется апексом перед каждом заходом на страницу и возвращает логичнское значение. Если эта функция возвращает false, пользователь "разлогинивается" и становится обычным неавторизованным пользователем, после чего перенаправляется на страницу логина (или другую страницу - об этом далее). В простейшем случае можно обойтись без нее;
  • на следующем шаге можно задать Session Verification Function. А можно и не задать - если на предыдущем шаге вы задали Page Sentry Function, то эту функцию задать уже нельзя. Все дело в том, что встроенная Page Sentry Function вызывает Session Verification Function, заданную вручную, а затем вызывает встроенную в апекс функцию верификации и объединяет оба результата через AND. У них примерно одинаковое предназначение, и если вам надо иметь возможность проверить какие-то особые условия и при их выполнении отказать в доступе, делайте это одним из способов;
  • на следующем шаге можно задать страницу, на которую будет перенаправляться пользователь в случае, если Page Sentry Function вернет false;
  • затем идет Pre-Authentication Process - процесс, выполняемый после ввода логина и пароля, но до их проверки. Здесь можно установить cookie, например, или сохранить в логе информацию о том, что кто-то пытался зайти;
  • следующий шаг - способ проверки логина и пароля (Authentication Function). Можно использовать один из встроенных или задать свою функцию.  Эта функция получит от движка апекса на вход две переменные - имя и пароль, введенные пользователем на странице логина (страницу логина апекс создаст автоматически при создании приложения с номером 101), и должна будет вернуть результат типа boolean. Поскольку мы уже решили, что встроенные механизмы проверки нам не подходят, мы выбираем свой способ и в появившемся окне вводим код (взят отсюда):
declare
  tmp_res number;
  CryptedPWD varchar2(32);  
begin
  -- Так как мы хорошие мальчики и девочки, мы никогда не храним пароль в базе в явном виде,
  -- а зашифровываем его как минимум хэш-функцией md5.
  -- Особо параноидальные личности, владеющие особо ценной (как им кажется) информацией,
  -- могут использовать любой другой алгоритм шифрования. Не забудьте только убедиться в том, что 
  -- при добавлении нового пользователя и при проверке его пароля вы используете один и тот же алгоритм,
  -- иначе результат вас несколько озадачит.

  -- Здесь мы хэшируем введенный пользователем пароль...
  CryptedPWD:=DBMS_OBFUSCATION_TOOLKIT.md5(input_string => p_password);

  -- ...и пытаемся найти в таблице USERS такую же пару логин - пароль:
  select count(*)
    into tmp_res
    from users
   where login = upper(p_username)
     and pwd = CryptedPWD;
 
  -- Сообщаем о результате: 0 строк = пароль неверный
return (tmp_res > 0);

  -- По-хорошему, нужно добавить проверку, а вдруг в таблице найдено больше одной записи...
  -- В следующий раз обязательно добавлю!
  exception
  when others then
  return false;  
end;
  • далее идет Post-Authentication Process - код, выполняемый после проверки пользователя;
  • задаем куки;
  • последний шаг - logout url. Этот URL появится в верхнем правом углу страницы на Navigation Bar - в специальной области, созданной для ссылок на страницы логина, регистрации, выхода, смены языка интерфейса и т. п. Например, можно взять такой:
wwv_flow_custom_auth_std.logout?p_this_flow=&APP_ID.&p_next_flow_page_sess=&APP_ID.:1

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

Включение схемы в приложение

Заходим на страницу приложения, нажимаем Edit Application Properties, там на закладке Security в разделе Authentication выбираем свою схему. Все, теперь все пользователи вашего приложения - это или пользователи из таблицы USER, или пользователь NOBODY. Естественно, все строки подстановки и PL/SQL переменные, содержащие имя текущего пользователя, будут содержать имена из вашей таблицы, введенные пользователем на странице логина.

7 комментариев:

  1. Здравствуйте. Только сейчас столкнулся с установкой доступа.

    И сразу непонятно. Какая эта версия Апекса?? У меня 4.1 и всего этого у меня нет.
    Вы писали:
    ""Саму схему можно создать в разделе Shared Components -> Authentication Schemes:
    нажимаем кнопочку Create;
    выбираем способ создания - From Scratch (то есть "с нуля");""

    Все что у меня доступно это
    Create Scheme: 1. Based on a pre-configured scheme from the gallery
    2. As a copy of an existing authentication scheme..

    Всех дальнейших строк нету. Если не сложно помогите разобраться

    ОтветитьУдалить
  2. Я не помню точно, где, но писал вроде, что у меня 4.0. Я просил хостера проапгрейдить мне workspace, но их индусская техподдержка кормила-кормила меня завтраками, но так и не сделала ничего :(. Так и сижу на 4.0...

    4.1 у меня была на виртуалке, но виртуалку я не трогал полтора года и она не запустилась :(((

    4.2 есть на apex.oracle.com. Там это выглядит так:
    Выбираем первый пункт (" Based on a pre-configured scheme from the gallery"), нажимаем "Next", на следующем шаге есть выпадающий список "Scheme type", в котором есть пункт "Custom". Если выбрать "Custom", то появляются дополнительные поля (хотя их вроде меньше, чем было в 4.0). Я так понимаю, это оно и есть.

    ОтветитьУдалить
  3. Вот такие функции(выпадающий список):

    Sentry Function Name
    Invalid Session Procedure Name
    Authentication Function Name
    Post Logout Procedure Name
    Enable Legacy Authentication Attributes

    ОтветитьУдалить
  4. У меня не очень много времени и нет готовой системы с кастомной авторизацией на версии 4.2. Подробно смогу написать через пару дней, когда все попробую и протестирую. Сейчас могу только сказать, что с вероятностью 99% Authentication Function Name в вашем списке - это Authentication Function из моего поста. Создаете функцию, тело берете из поста, придумываете имя, имя вписываете в это поле. Для кастомной схемы в 4.0 это был рабочий минимум, тут, возможно, еще что-то потребуется.

    ОтветитьУдалить
  5. Ой, там же 4.1 надо! Ну система та же. Приду домой, починю виртуалку, попробую, и т. д.

    ОтветитьУдалить
  6. нифига не понятно (((((

    ОтветитьУдалить
    Ответы
    1. Да, мне тоже иногда непонятно... Пишите подробнее, в чем ваша проблема, разберемся.

      Удалить