Выполнение аутентификации пользователя в Java EE / JSF, использующий j_security_check

Я задаюсь вопросом, что текущий подход расценивает аутентификацию пользователя для веб-приложения, использующего JSF 2.0 (и если какие-либо компоненты действительно существуют), и механизмы ядра Java EE 6 (полномочия/выходы из системы входа в систему/проверки) с информацией о пользователе содержат в объекте JPA. Учебное руководство EE Java Oracle немного редко на этом (только обрабатывает сервлеты).

Это, не используя целую другую платформу, как безопасность Spring (acegi) или Шов, но пытаясь придерживаться, надо надеяться, новой платформы Java EE 6 (веб-профиль), если это возможно.

155
задан BalusC 14 October 2014 в 20:32
поделиться

3 ответа

После поиска в Интернете и нескольких попыток различными способами, вот что я бы предложил для аутентификации Java EE 6:

Настройте область безопасности:

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

http://blog.gamatam.com/2009/11/jdbc-realm-setup -with-glassfish-v3.html

Примечание: в сообщении говорится о пользователе и таблице группы в базе данных. У меня был класс User с атрибутом перечисления UserType, сопоставленным с базой данных с помощью аннотаций javax.persistence. Я настроил область с той же таблицей для пользователей и групп, используя столбец userType в качестве столбца группы, и он работал нормально.

Использовать аутентификацию с помощью формы:

Продолжая следить за приведенным выше сообщением в блоге, настройте свои web.xml и sun-web.xml, но вместо использования BASIC-аутентификации используйте FORM (на самом деле, не имеет значения, какой из них вы используете , но в итоге я использовал FORM). Используйте стандартный HTML, а не JSF.

Затем воспользуйтесь советом BalusC, приведенным выше, о ленивой инициализации пользовательской информации из базы данных. Он предложил сделать это в управляемом компоненте, извлекающем принципала из контекста лиц.Вместо этого я использовал сессионный компонент с отслеживанием состояния для хранения информации о сеансе для каждого пользователя, поэтому я ввел контекст сеанса:

 @Resource
 private SessionContext sessionContext;

С помощью принципала я могу проверить имя пользователя и, используя EJB Entity Manager, получить информацию о пользователе из базу данных и хранить в моем 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, так же, как и я.

Чао,

Витор Соуза

84
ответ дан 23 November 2019 в 21:56
поделиться

Я полагаю, вам нужна аутентификация на основе форм с использованием дескрипторов развертывания и 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>

Вы можете выполнить отложенную загрузку в получателе Пользователь , чтобы проверить, вошел ли уже пользователь , а если нет, то проверьте, присутствует ли Принципал в запросе, и если да, то получите пользователя , связанного с 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;
    }

}

Пользователь , очевидно, доступен в JSF EL через # {auth.user} .

Для выхода выполните HttpServletRequest # logout () (и установите для пользователя значение null!). Вы можете получить дескриптор HttpServletRequest в JSF с помощью ExternalContext # 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-форму и bean-компонент со свойствами 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>

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

@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.
}

Таким образом, Пользователь доступен в JSF EL по # {user} .

148
ответ дан 23 November 2019 в 21:56
поделиться

Проблема HttpServletRequest.login не устанавливает состояние аутентификации в сеансе , исправлена ​​в 3.0.1. Обновите Glassfish до последней версии, и все готово.

Обновление довольно простое:

glassfishv3/bin/pkg set-authority -P dev.glassfish.org
glassfishv3/bin/pkg image-update
4
ответ дан 23 November 2019 в 21:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: