Выполнение аутентификации пользователя в Java EE / JSF с помощью проверки безопасности j
Мне интересно, каков текущий подход к аутентификации пользователей для веб-приложения, использующего JSF 2.0 (и если какие-либо компоненты существуют) и основные механизмы Java EE 6 (вход/проверка разрешений/выходов) с информацией о пользователе, хранящейся в сущности JPA. Учебник Oracle Java EE немного разрежен на этом (только обрабатывает сервлеты).
Это без используя целый другой фреймворк, например Spring-Security (acegi) или Seam, но пытаясь придерживаться надеюсь, с новой платформой Java EE 6 (веб-профиль), если это возможно.
4 ответа:
после поиска в интернете и пробовать много различных способов, вот что я бы предложил для аутентификации Java EE 6:
настройка области безопасности:
в моем случае, у меня были пользователи в базе данных. Поэтому я следил за этим сообщением в блоге, чтобы создать область JDBC, которая могла бы аутентифицировать пользователей на основе имени пользователя и MD5-хэшированных паролей в моей базе данных таблица:
http://blog.gamatam.com/2009/11/jdbc-realm-setup-with-glassfish-v3.html
Примечание: сообщение говорит о пользовательской и групповой таблице в базе данных. У меня есть класс пользователя с атрибутом пользовательского перечисления, подключенные с помощью пакета javax.аннотации сохраняемости к базе данных. Я настроил область с той же таблицей для пользователей и групп, используя столбец userType в качестве столбца группы, и он работал нормально.
используйте форму аутентификация:
все еще следуя приведенному выше сообщению в блоге, настройте свой веб.XML и солнце-интернет.xml, но вместо использования обычной проверки подлинности используйте форму (на самом деле, не имеет значения, какой из них вы используете, но я в конечном итоге использовал форму). Используйте стандартный HTML, а не JSF .
затем используйте совет BalusC выше при ленивой инициализации информации о пользователе из базы данных. Он предложил сделать это в управляемом Бобе, получая Принципал из контекста faces. Вместо этого я использовал stateful session bean для хранения информации о сеансе для каждого пользователя, поэтому я ввел контекст сеанса:
@Resource private SessionContext sessionContext;
С Принципалом я могу проверить имя пользователя и, используя EJB Entity Manager, получить информацию о пользователе из базы данных и сохранить в my
SessionInformation
EJB.выход из системы:
Я также огляделся в поисках лучшего способа выхода из системы. Лучшее, что я нашел, это использование сервлета:
@WebServlet(name = "LogoutServlet", urlPatterns = {"/logout"}) public class LogoutServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(false); // Destroys the session for this user. if (session != null) session.invalidate(); // Redirects back to the initial page. response.sendRedirect(request.getContextPath()); } }
хотя мой ответ действительно поздно, учитывая дату вопрос, я надеюсь, что это поможет другим людям, которые в конечном итоге здесь от Google, так же, как и я.
Чао,
Vítor Souza
я полагаю, вы хотите аутентификация на основе формы используя дескрипторы развертывания и
j_security_check
.вы также можете сделать это в JSF, просто используя те же предопределенные имена полей
j_username
иj_password
как показано в учебнике.например.
<form action="j_security_check" method="post"> <h:outputLabel for="j_username" value="Username" /> <h:inputText id="j_username" /> <br /> <h:outputLabel for="j_password" value="Password" /> <h:inputSecret id="j_password" /> <br /> <h:commandButton value="Login" /> </form>
вы можете сделать ленивую загрузку в
User
геттер, чтобы проверить, еслиUser
уже вошел в систему, а если нет, то проверьте, еслиPrincipal
присутствует в запрос и если да, то получитьUser
связан сj_username
.package com.stackoverflow.q2206911; import java.io.IOException; import java.security.Principal; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; import javax.faces.context.FacesContext; @ManagedBean @SessionScoped public class Auth { private User user; // The JPA entity. @EJB private UserService userService; public User getUser() { if (user == null) { Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal(); if (principal != null) { user = userService.find(principal.getName()); // Find User by j_username. } } return user; } }
The
User
очевидно доступен в JSF EL by#{auth.user}
.для выхода из системы сделайте
HttpServletRequest#logout()
(иUser
к нулю!). Вы можете получить ручкуHttpServletRequest
в JSF byExternalContext#getRequest()
. Вы также можете просто аннулировать сеанс в целом.public String logout() { FacesContext.getCurrentInstance().getExternalContext().invalidateSession(); return "login?faces-redirect=true"; }
для остатка (определение пользователей, ролей и ограничений в дескрипторе развертывания и область), просто следуйте инструкциям Java EE 6 и документации servletcontainer обычным способом.
обновление: вы также можете использовать новый сервлет 3.0
HttpServletRequest#login()
чтобы сделать программный вход вместо использованияj_security_check
которые могут быть недоступны диспетчером в некоторых сервлетконтейнерах. В этом случае вы можете использовать полноценную форму JSF и боб сusername
иpassword
"свойства" иlogin
метод, который выглядит как это:<h:form> <h:outputLabel for="username" value="Username" /> <h:inputText id="username" value="#{auth.username}" required="true" /> <h:message for="username" /> <br /> <h:outputLabel for="password" value="Password" /> <h:inputSecret id="password" value="#{auth.password}" required="true" /> <h:message for="password" /> <br /> <h:commandButton value="Login" action="#{auth.login}" /> <h:messages globalOnly="true" /> </h:form>
и это представление с областью управляемого компонента, который также запоминает первоначально запрошенную страницу:
@ManagedBean @ViewScoped public class Auth { private String username; private String password; private String originalURL; @PostConstruct public void init() { ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI); if (originalURL == null) { originalURL = externalContext.getRequestContextPath() + "/home.xhtml"; } else { String originalQuery = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_QUERY_STRING); if (originalQuery != null) { originalURL += "?" + originalQuery; } } } @EJB private UserService userService; public void login() throws IOException { FacesContext context = FacesContext.getCurrentInstance(); ExternalContext externalContext = context.getExternalContext(); HttpServletRequest request = (HttpServletRequest) externalContext.getRequest(); try { request.login(username, password); User user = userService.find(username, password); externalContext.getSessionMap().put("user", user); externalContext.redirect(originalURL); } catch (ServletException e) { // Handle unknown username/password in request.login(). context.addMessage(null, new FacesMessage("Unknown login")); } } public void logout() throws IOException { ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); externalContext.invalidateSession(); externalContext.redirect(externalContext.getRequestContextPath() + "/login.xhtml"); } // Getters/setters for username and password. }
таким образом
User
доступно в JSF EL by#{user}
.
следует отметить, что это возможность полностью оставить проблемы аутентификации на передний контроллер, например, веб-сервер Apache и оценить HttpServletRequest.вместо этого getRemoteUser (), который является представлением JAVA для переменной среды REMOTE_USER. Это позволяет также сложные конструкции входа в систему, такие как проверка подлинности Shibboleth. Фильтрация запросов к контейнеру сервлетов через веб-сервер является хорошим дизайном для производственных сред, часто используется mod_jk так.
вопрос HttpServletRequest.login не устанавливает состояние аутентификации в сеансе была исправлена в версии 3.0.1. Обновите glassfish до последней версии, и все готово.
обновление довольно проста:
glassfishv3/bin/pkg set-authority -P dev.glassfish.org glassfishv3/bin/pkg image-update