понедельник, 25 февраля 2013 г.

1й - Практикум. Oracle ADF. Шаблон, Форма, Авторизация, Bean,...

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


  Но в начале нам потребуется Jdeveloper. После установки откройте закладку с серверами и  запустите экземпляр встроенного сервера Weblogic (WLS).

Настройка его простая. После того как WLS настроен, делаем первое приложение. Для удобного дизайна приложения предлагаю расположить следующие закладки в JDeveloper:
Projects, Structure, Component palette,  Property Insperor, Message log

В  меню Tools-Preferences-Environment  выбрать Encoding "UTF-8" .

Создание приложения. Из меню создать выбираем.


 






Укажем имя приложения, префикс java пакета.

Продолжим выполнения мастера по шагам.
После выполнения мастера, делаем первый шаблон для форм см. картинку.



Выбираем из предустановленных шаблонов, шаблон для нашего. Добавляем области (facet) в которые в дальнейшем можно будет вносить изменения уже в страницах. Пока их две слева, и главная.
Даем название, указываем размещение, можно указать еще атрибуты, это вроде переменных.
После создание шаблона, надо указать  где на шаблоне будут располагаться эти области.
Из палитры компонент перетащить на шаблон компоненту "Facet Definition". Два раза,каждый для своей области. На шаблоне в верхней области размещаем PanelGroupLayout с горизонтальной ориентацией. Размещать компоненты на форме, можно перетаскивая компонент из палитры компонент на форму, на структуру. Или находясь в структуре через контекстное меню, добавлять компоненты. В PanelGroupLayout положить две другие компоненты outputText и goImageLink.
Вот что получится: в структуре и исходном коде:
 
                    <af:panelGroupLayout id="pt_pgl1">
                        <af:panelGroupLayout id="pt_pgl2" layout="horizontal" halign="right">
                            <af:outputText value="#{securityContext.userName}" id="pt_ot1"/>
                            <af:goImageLink destination='#{securityContext.authenticated ?
                            "/adfAuthentication?logout=true&amp;end_url=/faces/login.jsf" :
                            "/adfAuthentication?success_url=/faces/auto/index.jsf"}' id="pt_gl1_toptemp2"
                                            icon="/images/Exit.png"
                                            shortDesc='#{securityContext.authenticated ? "Выход" : "Вход"}'/>
                        </af:panelGroupLayout>

С помощью EL выражений в эти компоненты выводятся имя пользователя, и сылки для servlet авторизации. Так например для goImageLink атрибута Destination, EL выглядит так:

 Что в EL доступно для securityContext можно посмотреть здесь. Про EL можно почитать здесь.

Теперь можно сделать первую страницу. Там же где выбирали создание шаблона, выбираем создание страницы. Выбираем ранее созданный шаблон.

Подготовим теперь Bean - "MainBean". Для проекта ViewController создать java class, указав имя и пакет для размещения.   
В ADF всегда по умолчание есть одно taskFlow (Unbounded) которое создается по умолчанию, это adfc-config (Находится ViewController - Page Flows). С него можно делать все первые инициализации, запуски страниц, создание бинов и др. Разместим в нем страницу Index.




Теперь надо подготовить taskFlow с фрагментами. Есть фрагменты страниц которые можно использовать в  taskFlow соответствующего типа - "Use Page Frafment", в свою очередь эти фрагменты можно повторно использовать в других местах приложения. Вместе, страницы и taskFlow дают мощный механизм.

     
Перетащим фрагмент страницу на taskFlow (task-flow-main).
А taskFlow в свою очередь на страницу index, используя регион.

В taskFlow (adfc-config) зарегистрируем bean "mainBean" scope которого - reqiest т.е. пока идет запрос с клиента, создается экземпляр и живет в течении этого запроса.


В классе "MainBean" добавим поля:
 









В taskFlow  (adfc-config) добавим страницу login и соединим с index (Control flow case)


 Сделаем дизайн страницы login примерно так:

<af:panelStretchLayout id="psl1" topHeight="30%" startWidth="30%">
                <f:facet name="bottom"/>
                <f:facet name="center">
                    <af:panelFormLayout id="pfl1">
                        <f:facet name="footer">
                            <af:commandButton text="Login" id="cb1" action="#{mainBean.doLogin}"/>
                        </f:facet>
                        <af:inputText label="Имя" id="it1" required="true" value="#{mainBean.login}"/>
                        <af:inputText label="Пароль" id="it2" required="true" value="#{mainBean.password}"/>
                    </af:panelFormLayout>
                </f:facet>
                <f:facet name="start">
                    <af:spacer width="100%" height="10" id="s1"/>
                </f:facet>
                <f:facet name="end"/>
                <f:facet name="top">
                    <af:spacer width="100%" height="10" id="s2"/>
                </f:facet>
</af:panelStretchLayout>



Поля формы подключены к бину "mainBean", кнопка вызывает метод через EL #{mainBean.doLogin}. Метод doLogin:


public String doLogin() {
        try {
            if (login == null || password == null) {
                addMessage(FacesMessage.SEVERITY_WARN, "Login", "Укажите имя и пароль");
                return null;
            }

            String user = login.toLowerCase();
            byte[] pass = password.getBytes();

            FacesContext ctx = FacesContext.getCurrentInstance();
            HttpServletRequest request = (HttpServletRequest)ctx.getExternalContext().getRequest();

            CallbackHandler handler = new URLCallbackHandler(user, pass);
            Subject mySubject = Authentication.login(handler);
            ServletAuthentication.runAs(mySubject, request);
            ServletAuthentication.generateNewSessionID(request);
           
            HttpServletResponse response = (HttpServletResponse) ctx.getExternalContext().getResponse();
            sendForward(request, response, "/adfAuthentication?success_url=/faces/index.jsf");
           
        } catch (FailedLoginException fle) {
            System.out.println(fle);
            addMessage(FacesMessage.SEVERITY_ERROR, "Login", fle.getMessage());
        } catch (Exception le) {
            System.out.println(le.getMessage());
            addMessage(FacesMessage.SEVERITY_ERROR, "Login", le.getMessage());
        }
        return null;
    }

Создадим еще две страницы login.jsf и error.jsf - пока пустые, для авторизации. Теперь можно подключить фукционал ADF Security. Через меню Application-Sesure-Configure ADF Security
Далее надо указать ранее подготовленные страницы login и error используя /faces/


Настраиваем Security.  Из меню выбираем Application-Secure-Resource Grants  и для taskFlow (task-flow-main)  указываем доступ роли "authenticated-role", т.е. тем кто авторизован. Если теперь попробовать запустить страницу index, то мы будем переадресованы, на login и только после авторизации получим доступ.

 Для проверки авторизации надо завести на WLS пользователя. Запускаем WLS.



Запускаем консоль управления WLS - http://localhost:7101/console/, авторизуемся, идем в Security Realms - myrealm- Users adnd Groups и добавляем пользователя.

 Теперь можно запустить приложение.

Хочу заметить, есть какой то баг. Авторизация на браузере IE работает не корректно. Поэтому предлагаю тестировать на других. 
Для того что бы сделать ссылку на приложение более читабельной, можно изменить имя приложения в свойствах проекта ViewController:

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

Ссылку на приложение всегда можно получить вот здесь:


 
Остановить приложение и/или сервер можно отсюда -



Источник:
Enabling ADF Security in a Fusion Web Application
http://docs.oracle.com/cd/E16162_01/web.1112/e16182/adding_security.htm#BGBGJEAH


Исходный код приложения- Практикум - 1





 





4 комментария:

  1. Александр, спасибо за статью!
    Возможна ли организовать авторизацию не через WLS, а через "самописную" систему(на pl\sql)?

    ОтветитьУдалить
    Ответы
    1. Да я думаю что может помочь SQL Authentication provider. Делается так,на WLS в "Security Realms >myrealm", добавляется новый тип провайдера (в Providers) - SQLAuthenticator. Далее на вкладке "Provider Specific" надо указать запросы которые будут извлекать, проверять и пр., пользователя. Ну а в запросах можно организовать вызов PL/SQL

      Удалить
    2. Да и нужно еще настроить порядок "Reorder Authentication Providers" и в настройках провайдера указать "Control flag" -"Sufficient"

      Удалить
    3. Или написать свой - Custom Security Providers.
      Документация - http://docs.oracle.com/cd/E12890_01/ales/docs32/dvspisec/progrmng.html

      Удалить