Статьи

JDBC Realm и аутентификация на основе форм с GlassFish 3.1.2.2 и Primefaces 3.4

Одна из самых популярных публикаций в моем блоге — это краткое руководство по JDBC Security Realm и аутентификации на основе форм на GlassFish с Primefaces . После того, как я получил некоторые комментарии о том, что он больше не работает с последней версией GlassFish 3.1.2.2, я подумал, что, возможно, пришло время вернуться к ней и представить обновленную версию. Вот так:

подготовка

Как и в оригинальном уроке, я собираюсь положиться на некоторые вещи. Убедитесь, что установлена ​​последняя бета-версия NetBeans 7.3 (которая включает GlassFish 3.1.2.2) и MySQL Community Server (5.5.x). Вы должны были убедиться, что все работает, и вы можете запустить GlassFish и MySQL Server также запущен.

Некоторые основы

Область проверки подлинности GlassFish, также называемая доменом политики безопасности или доменом безопасности, является областью, в которой сервер GlassFish определяет и применяет общую политику безопасности. Сервер GlassFish предварительно сконфигурирован с областями файлов, сертификатов и администрирования. Кроме того, вы можете настроить LDAP, JDBC, дайджест, Oracle Solaris или пользовательские области. Приложение может указать, какую область использовать в своем дескрипторе развертывания. Если вы хотите сохранить учетные данные пользователя для вашего приложения в базе данных, ваш первый выбор — это сфера JDBC.

Подготовьте базу данных


Запустите NetBeans и перейдите на вкладку «Службы». Щелкните правой кнопкой мыши узел «Базы данных» и выберите «Зарегистрировать MySQL Server». Заполните детали вашей установки и нажмите «ОК». Щелкните правой кнопкой мыши новый узел MySQL и выберите «подключиться». Теперь вы видите все уже имеющиеся базы данных. Снова щелкните правой кнопкой мыши и выберите «Создать базу данных». Введите ‘jdbcrealm’ в качестве нового имени базы данных. Примечание: мы не собираемся делать все это с отдельным пользователем базы данных. Это то, что настоятельно рекомендуется, но я использую пользователя root в этом примере. Если у вас есть пользователь, вы также можете предоставить полный доступ к нему здесь. Нажмите «ОК». Вы автоматически подключаетесь к вновь созданной базе данных. Разверните узел жирным шрифтом и щелкните правой кнопкой мыши «Таблицы». Выберите «Выполнить команду» или введите данные таблицы с помощью мастера.

01
02
03
04
05
06
07
08
09
10
11
CREATE TABLE USERS (
  `USERID` VARCHAR(255) NOT NULL,
  `PASSWORD` VARCHAR(255) NOT NULL,
  PRIMARY KEY (`USERID`)
);
 
CREATE TABLE USERS_GROUPS (
  `GROUPID` VARCHAR(20) NOT NULL,
  `USERID` VARCHAR(255) NOT NULL,
  PRIMARY KEY (`GROUPID`)
);

Это все на данный момент с базой данных. Перейдите к следующему абзацу.

Дайте GlassFish знать о MySQL

Первое, что нужно сделать, это получить последнюю и лучшую версию MySQL Connector / J с веб-сайта MySQL, который на момент написания этой статьи составлял 5.1.22. Извлеките файл mysql-connector-java-5.1.22-bin.jar и поместите его в папку своего домена (например, glassfish \ domains \ domain1 \ lib). Готово. Теперь, наконец, пришло время создать проект.

Базовая настройка проекта

Запустите новый проект веб-приложения на основе Maven. Выберите «Новый проект»> «Maven»> «Веб-приложение» и нажмите «Далее». Теперь введите имя (например, secureapp) и все необходимые maven corinates и нажмите «Далее». Выберите настроенный сервер GlassFish 3+. Выберите Java EE 6 Web в качестве версии EE и нажмите «Готово». Теперь нам нужно добавить еще несколько настроек в наш домен GlassFish. Щелкните правой кнопкой мыши по вновь созданному проекту и выберите «Создать> Прочее> GlassFish> Пул соединений JDBC». Введите имя для нового пула соединений (например, SecurityConnectionPool) и под флажком «Извлечь из существующего соединения:» выберите свое зарегистрированное соединение MySQL. Нажмите «Далее. просмотрите свойства пула соединений и нажмите «Готово». Недавно созданная папка «Ресурсы сервера» теперь показывает ваш файл sun-resources.xml. Следуйте инструкциям и создайте «New> Other> GlassFish> JDBC Resource», указывающий созданный SecurityConnectionPool (например, jdbc / securityDatasource). Вы найдете настроенные вещи в «Other Sources / setup» в файле с именем glassfish-resources.xml , Он развертывается на вашем сервере вместе с вашим приложением. Так что вам не нужно заботиться о настройке всего с помощью консоли администратора GlassFish. Кроме того, нам все еще нужны Primefaces. Щелкните правой кнопкой мыши по своему проекту, выберите «Свойства», перейдите в категорию «Рамки» и добавьте «JavaServer Faces». Перейдите на вкладку «Компоненты» и выберите «PrimeFaces». Завершите, нажав «ОК». Вы можете проверить, сработало ли это, открыв pom.xml и проверив наличие зависимости Primefaces. 3.4 должен быть там. Не стесняйтесь менять версию на последнюю 3.4.2.

Конечная конфигурация GlassFish

Теперь пришло время запустить GlassFish и выполнить настройку области. В NetBeans снова перейдите на вкладку «Службы» и щелкните правой кнопкой мыши узел «GlassFish 3+». Выберите «Пуск» и посмотрите окно вывода для успешного запуска. Снова щелкните правой кнопкой мыши и выберите «View Domain Admin Console», после чего откроется браузер по умолчанию, указывающий на http: // localhost: 4848 /. Выберите «Конфигурации> Конфигурация сервера> Безопасность> Области» и нажмите «Создать…» в верхней части таблицы. Введите имя (например, JDBCRealm) и выберите com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm из раскрывающегося списка. Введите следующие значения в текстовые поля:

JAAS jdbcRealm
JNDI JDBC / securityDatasource
Таблица пользователей пользователи
Колонка имени пользователя имя пользователя
Колонка паролей пароль
Групповая таблица группы
Колонка Имя группы имя группы

Оставьте все остальные значения по умолчанию / пробелы и выберите «ОК» в верхнем правом углу. Вам предоставляется необычное окно предупреждения JavaScript, в котором вам не нужно оставлять поле алгоритма дайджеста пустым. Я поставил ошибку об этом. По умолчанию это SHA-256. Что отличается от версий GlassFish до 3.1, которые использовали MD5 здесь. В более старой версии этого учебника алгоритм дайджеста вообще не использовался («нет»). Это должно было сделать вещи проще, но вообще не считается хорошей практикой. Итак, давайте придерживаться SHA-256 даже для разработки, пожалуйста.

Защитите ваше приложение

Закончено с настройкой вашей среды. Теперь нам нужно защитить приложение. Первая часть — подумать о ресурсах для защиты. Перейдите в папку «Веб-страницы» и создайте еще две папки. Один называется «admin», а другой — «users». Идея заключается в том, чтобы иметь две отдельные папки, к которым могут обращаться пользователи, принадлежащие к соответствующим группам. Теперь нам нужно создать несколько страниц. Откройте веб-страницы / index.xhtml и замените все, что находится между тегами h: body, следующим текстом:

1
2
3
4
5
6
<h:body>
       Select where you want to go:
       <br />
       <h:link outcome='admin/index' value='To the admin section' /><br />
       <h:link outcome='users/index' value='To the user section' />
   </h:body>

Теперь добавьте новый index.xhtml в пользовательские и административные папки. Заставьте их сделать что-то вроде этого:

1
2
3
4
5
<h:body>
       <h1>Hello Admin|User</h1>
       <br />
       <h:link outcome='/index' value='Back to Homepage' />
   </h:body>

На логин.xhtml. Создайте его со следующим содержимым в корневом каталоге вашей веб-страницы.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
      xmlns:p='http://primefaces.org/ui'
      xmlns:h='http://java.sun.com/jsf/html'>
    <h:head>
        <title>Login Form</title>
    </h:head>
    <h:body>
        <p:panel header='Login From'>
            <form method='POST' action='j_security_check'>
                Username: <input type='text' name='j_username' />
                Password: <input type='password' name='j_password' />
                <br />
                <input type='submit' value='Login' />
                <input type='reset' value='Reset' />
            </form>
        </p:panel>
    </h:body>
</html>

Как видите, у вас есть базовый компонент Primefaces p: panel, имеющий простую HTML-форму, которая указывает на предопределенное действие j_security_check. Здесь происходит вся магия. Вы также должны включить два поля ввода для имени пользователя и пароля с предопределенными именами j_username и j_password. Теперь мы собираемся создать loginerror.xhtml, который отображается, если пользователь не ввел правильные учетные данные. (используйте тот же DOCTYPE и заголовок, что и в примере выше).

1
2
3
4
5
<h:body>
       <p:panel header='Login Error'>
           Sorry, you made an Error. Please try again: <a href='#{facesContext.externalContext.requestContextPath}/' >Login</a>
       </p:panel>
   </h:body>

Единственное волшебство здесь — ссылка href якоря входа. Нам нужно получить правильный контекст запроса, и это можно сделать путем доступа к контексту лица. Если пользователь без соответствующих прав пытается получить доступ к папке, ему предоставляется страница ошибки 403 «Отказано в доступе». Если вы хотите настроить его, вам нужно добавить его и добавить следующие строки в ваш web.xml:

1
2
3
4
<error-page>
<error-code>403</error-code>
<location>/faces/403.xhtml</location>
</error-page>

Это означает, что все не авторизованные запросы должны идти на страницу 403. Если у вас уже открыт web.xml, давайте начнем защищать ваше приложение. Нам нужно добавить ограничение безопасности для любого защищенного ресурса. Ограничения безопасности менее всего понятны веб-разработчикам, даже если они критически важны для безопасности веб-приложений Java EE. Указание комбинации шаблонов URL, методов HTTP, ролей и транспортных ограничений может быть затруднительным для программиста или администратора. Важно понимать, что любая комбинация, которая была предназначена для обеспечения безопасности, но не была указана с помощью ограничений безопасности, будет означать, что веб-контейнер будет разрешать эти запросы. Ограничения безопасности состоят из коллекций веб-ресурсов (шаблоны URL, методы HTTP), ограничения авторизации (имена ролей) и ограничений пользовательских данных (необходимость получения веб-запроса через защищенный транспорт, такой как TLS).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<security-constraint>
       <display-name>Admin Pages</display-name>
       <web-resource-collection>
           <web-resource-name>Protected Admin Area</web-resource-name>
           <description></description>
           <url-pattern>/faces/admin/*</url-pattern>
           <http-method>GET</http-method>
           <http-method>POST</http-method>
           <http-method>HEAD</http-method>
           <http-method>PUT</http-method>
           <http-method>OPTIONS</http-method>
           <http-method>TRACE</http-method>
           <http-method>DELETE</http-method>
       </web-resource-collection>
       <auth-constraint>
           <description/>
           <role-name>admin</role-name>
       </auth-constraint>
       <user-data-constraint>
           <transport-guarantee>NONE</transport-guarantee>
       </user-data-constraint>
   </security-constraint>
   <security-constraint>
       <display-name>All Access</display-name>
       <web-resource-collection>
           <web-resource-name>None Protected User Area</web-resource-name>
           <description/>
           <url-pattern>/faces/users/*</url-pattern>
           <http-method>GET</http-method>
           <http-method>POST</http-method>
           <http-method>HEAD</http-method>
           <http-method>PUT</http-method>
           <http-method>OPTIONS</http-method>
           <http-method>TRACE</http-method>
           <http-method>DELETE</http-method>
       </web-resource-collection>
       <user-data-constraint>
           <transport-guarantee>NONE</transport-guarantee>
       </user-data-constraint>
   </security-constraint>

Если ограничения существуют, вы должны определить, каким образом контейнер должен бросить вызов пользователю. Веб-контейнер может аутентифицировать веб-клиента / пользователя с использованием схем аутентификации HTTP BASIC, HTTP DIGEST, HTTPS CLIENT или FORM. В этом случае мы используем аутентификацию на основе форм и определяем JDBCRealm

1
2
3
4
5
6
7
8
<login-config>
        <auth-method>FORM</auth-method>
        <realm-name>JDBCRealm</realm-name>
        <form-login-config>
            <form-login-page>/faces/login.xhtml</form-login-page>
            <form-error-page>/faces/loginerror.xhtml</form-error-page>
        </form-login-config>
    </login-config>

Имя области должно быть именем, назначенным ранее области безопасности. Закройте файл web.xml и откройте файл sun-web.xml, чтобы сопоставить имена ролей приложений с реальными группами в базе данных. Эта абстракция кажется странной, но у нее есть несколько причин. Он был введен, чтобы иметь возможность сопоставления ролей приложений с различными именами групп на предприятиях. Я никогда не видел, чтобы это широко использовалось, но эта функция есть, и вы должны настроить ее. Другие серверы приложений предполагают, что если сопоставление отсутствует, имена ролей и имена групп совпадают. GlassFish так не считает. Поэтому вы должны поместить следующее в glassfish-web.xml. Вы можете создать его, щелкнув правой кнопкой мыши на папке WEB-INF вашего проекта, выбрав «New> Other> GlassFish> GlassFish Descriptor»

1
2
3
4
<security-role-mapping>
    <role-name>admin</role-name>
    <group-name>admin</group-name>
</security-role-mapping>

Это было _основно_ … все, что вам нужно, на месте. Единственное, чего не хватает — это пользователей в базе данных. Он все еще пуст … Нам нужно добавить тестового пользователя:

Добавление тестового пользователя в базу данных

И снова мы начнем с щелчка правой кнопкой мыши по базе данных jdbcrealm на вкладке «Службы» в NetBeans. Выберите «Выполнить команду» и вставьте следующее:

1
2
INSERT INTO USERS VALUES ('admin', '8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918');
INSERT INTO USERS_GROUPS VALUES ('admin', 'admin');

Вы можете войти через пользователя: admin и пароль: admin и получить доступ к защищенной области. Пример кода для генерации хеша может выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
try {
           MessageDigest md = MessageDigest.getInstance('SHA-256');
           String text = 'admin';
           md.update(text.getBytes('UTF-8')); // Change this to 'UTF-16' if needed
           byte[] digest = md.digest();
           BigInteger bigInt = new BigInteger(1, digest);
           String output = bigInt.toString(16);
 
           System.out.println(output);
 
       } catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
           Logger.getLogger(PasswordTest.class.getName()).log(Level.SEVERE, null, ex);
 
       }

Ссылка: аутентификация JDBC Realm и Form-based с помощью GlassFish 3.1.2.2 и Primefaces 3.4 от нашего партнера JCG Маркуса Эйзела ( Markus Eisele) из блога Enterprise Software Development с Java .