2013-03-25 4 views
0

Этот вопрос является продолжением here.Как установить UserBean при использовании JSF 2.0, CDI, EJB 3.1 Servlet Spec 3.0 Программная безопасность

При входе в систему мое приложение должно проконсультироваться с контейнером для аутентификации с помощью request.login(), а затем установить «Пользовательский» компонент, который содержит имя пользователя, пароль, роль и поле для определения местоположения. После успешной авторизации против контейнера (WAS 8) необходимо проверить роль пользователя, чтобы определить подходящую страницу приветствия, на которой пользователь должен быть перенаправлен. Мой контейнер реализует федеративный репозиторий, который в основном объединяет 3 ветви LDAP, базу данных и плоский файл. Существует много ролей (5 на данный момент, вероятно, будет более поздним).

У меня есть 2 beans: компонент RequestScoped Credentials и SessionScoped bean с именем Login. Вход содержит метод login(). У меня проблема с методом входа в систему.

Моя проблема заключается в том, что всякий раз, когда я использую:

Principal userPrincipal = request.getUserPrincipal(); 
request.getUserPrincipal(); 
if (userPrincipal != null) { 
    request.logout(); 
} 
request.login(credentials.getUsername(), credentials.getPassword()); 
String name = userPrincipal.getName(); 

перед:

Donor donor = loginService.getDonor(credentials.getUsername()); 
currentUser = new Users(); 
currentUser.setLocation(donor.getCenter().getCity()); 
currentUser.setRole("DONOR"); 
currentUser.setUserId(credentials.getUsername()); 
currentUser.setFirstName(donor.getFirstName()); 
currentUser.setLastName(donor.getLastName()); 
currentUser.setUsername(credentials.getUsername()); 
currentUser.setName(credentials.getUsername()); 
return "users?faces-redirect=true"; 

мой боб CurrentUser Пользователь не хранится в сессии.

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

if (userPrincipal != null) { 
    request.logout(); 
} 

вызывает проблему.

Как я должен хранить пользовательский компонент, реализующий программную безопасность и JSF2.0/CDI? Я провел недели на этом. Я могу представить себе что-то более сложное, как фильтр, который ловит перенаправление, захватывает пользовательский интерфейс, вызывает db или ldap для дополнительных атрибутов, а затем перенаправляется на соответствующую страницу ... но я хочу, чтобы все было просто. Там должен быть простой способ сделать это.

Первоначально я попробовал свою руку при входе в систему с помощью j_security_check и указав FORM в web.xml. Теперь, используя форму JSF 2.0 и метод входа в систему, я заметил, что FORM игнорируется в пользу BASIC. System.out.println ("getAuthType? .." + request.getAuthType()); возвращает «BASIC» в методе входа. Это приводит к раздражающему кешу, поэтому требуется request.logout. В противном случае request.login не удастся.

Вчера вечером я наткнулся на this, в котором содержится ссылка на here. Таким образом, может быть способ получить userprincipal, установить пользовательский компонент и перенаправить на соответствующую страницу приветствия. Я не знаю, как устарела эта 2-я ссылка. Также представляется, что j_security_check нельзя использовать в тандеме с программным средством определения, на какой странице я должен перенаправить пользователя на роль.

Что касается использования j_security_check или программной безопасности/JSF/CDI, мне просто нужно выяснить, что-то простое, и позволяет мне хранить логический элемент входа или независимый пользовательский компонент в сеансе.

Вот мой Логин форма с моей точки зрения:

<h:form id="loginForm"> 
    <fieldset> 
     <div class="form-row"> 
      <h:outputLabel for="username" value="User ID"/> 
      <h:inputText id="username" value="#{credentials.username}" 
required="true" size="20" /> 
     </div> 
     <div class="form-row"> 
      <h:outputLabel for="password" value="Password"/> 
      <h:inputSecret id="password" type="password" value="# 
{credentials.password}" required="true" /> 
     </div> 

     <div class="form-row"> 
      <h:commandButton styleClass="btn btn-warning" value="Sign In" 
type="submit" action="#{login.login}" /> 
      <a href="#" id="forgot-password">Forgot you password?</a> 
     </div>  
    </fieldset> 
</h:form> 

Вот мой Логин боб (код был раздели и редактируются только продемонстрировать соответствующие части):

import javax.enterprise.context.SessionScoped; 
import javax.enterprise.inject.Produces; 
import javax.faces.application.FacesMessage; 
import javax.faces.context.ExternalContext; 
import javax.faces.context.FacesContext; 
import javax.inject.Inject; 
import javax.inject.Named; 
import javax.persistence.EntityManager; 
import javax.persistence.PersistenceContext; 
import javax.security.auth.Subject; 
import javax.security.auth.login.CredentialExpiredException; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServletRequest; 
import java.security.Principal; 
@SessionScoped 
@Named 
public class Login implements Serializable { 

    private static final long serialVersionUID = 7965455427888195913L; 

    @Inject 
    private Credentials credentials; 

    @PersistenceContext 
    private EntityManager userDatabase; 

    @Inject 
    LoginService loginService; 

    private Users currentUser; 
    private Service service; 
    private String uniqueSecurityName; 
    private String l; 

    @SuppressWarnings("unchecked") 
    public String login() { 
     FacesContext context = FacesContext.getCurrentInstance(); 
     ExternalContext externalContext = context.getExternalContext(); 
     HttpServletRequest request = (HttpServletRequest) externalContext.getRequest(); 
     System.out.println("The login method has been called."); 

     try { 
     Principal userPrincipal = request.getUserPrincipal(); 
     request.getUserPrincipal(); 
     if (userPrincipal != null) { 
      request.logout(); 
     } 
     request.login(credentials.getUsername(), credentials.getPassword()); 
     String name = userPrincipal.getName(); 

     System.out.println("getRemoteUser?.." + request.getRemoteUser()); 
     System.out.println("getUserPrincipal?.." + request.getUserPrincipal()); 
     System.out.println("getAuthType?.." + request.getAuthType());   

     Donor donor = loginService.getDonor(credentials.getUsername()); 
     currentUser = new Users(); 
     currentUser.setLocation(donor.getCenter().getCity()); 
     currentUser.setRole("DONOR"); 
     currentUser.setUserId(credentials.getUsername()); 
     currentUser.setFirstName(donor.getFirstName()); 
     currentUser.setLastName(donor.getLastName()); 
     currentUser.setUsername(credentials.getUsername()); 
     currentUser.setName(credentials.getUsername()); 
     return "users?faces-redirect=true"; 
     } catch (Exception e) {} 

     return null; 
    } 
    public void logout() { 
     currentUser = null; 
    } 

    public boolean isLoggedIn() { 
     return currentUser != null; 
    } 

    @Produces 
    @LoggedIn 
    public Users getCurrentUser() { 
     return currentUser; 
    } 
} 

Вот мой Credentials боб :

import java.io.Serializable; 

import javax.enterprise.context.RequestScoped; 
import javax.enterprise.inject.Default; 
import javax.inject.Named; 

@RequestScoped 
@Named 
@Default 
public class Credentials implements Serializable { 
    /** 
    * 
    */ 
    private static final long serialVersionUID = 6976596855571123825L; 
    private String username; 
    private String password; 

    public String getUsername() { 
     return username; 
    } 

    public void setUsername(String username) { 
     this.username = username; 
    } 

    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 
} 

Адрес следующей страницы users.xhtml (для проверки на проверку s ession информация):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
     xmlns:ui="http://java.sun.com/jsf/facelets" 
     xmlns:h="http://java.sun.com/jsf/html" 
     xmlns:f="http://java.sun.com/jsf/core"> 
     <head> 
     <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> 
     <title>Login</title> 
     <link href="style/main.css" rel="stylesheet" type="text/css"/> 
     <ui:insert name="head"/> 
    </head> 
<body> 

    <div id="container"> 
    <div id="header"> 

    </div> 

    <div id="sidebar"> 

    </div> 

    <div id="content"> 
     <h1>Current User</h1> 
     <h:dataTable value="#{login.currentUser}" var="u"> 
      <h:column> 
       <f:facet name="header"> 
       Username 
       </f:facet> 
       <h:outputText value="#{u.username}" /> 
      </h:column> 
      <h:column> 
       <f:facet name="header"> 
       Name 
       </f:facet> 
       <h:outputText value="#{u.name}" /> 
      </h:column> 
      <h:column> 
       <f:facet name="header"> 
       Password 
       </f:facet> 
       <h:outputText value="#{u.password}" /> 
      </h:column> 
     </h:dataTable> 
    </div> 

    <br style="clear:both"/> 
    </div> 

</body> 
</html> 

Вот мой Пользователи боб:

import java.io.Serializable; 

import javax.annotation.PostConstruct; 
import javax.enterprise.context.SessionScoped; 
import javax.faces.context.FacesContext; 
import javax.inject.Named; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.Transient; 

@Entity 
public class Users { 
    @Id 
    private String username; 
    private String name; 
    private String password; 
    @Transient 
    private String role; 
    @Transient 
    private String location; 
    @Transient 
    private String userId; 
    @Transient 
    private String firstName; 
    @Transient 
    private String lastName; 

    public Users() { 
    } 

    public String getUsername() { 
     return username; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public void setUsername(String username) { 
     this.username = username; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 

    public String getPassword() { 
     return password; 
    } 

    public String getRole() { 
     return role; 
    } 

    public void setRole(String role) { 
     this.role = role; 
    } 

    public String getLocation() { 
     return location; 
    } 

    public void setLocation(String location) { 
     this.location = location; 
    } 

    public String getUserId() { 
     return userId; 
    } 

    public void setUserId(String userId) { 
     this.userId = userId; 
    } 

    public String getFirstName() { 
     return firstName; 
    } 

    public void setFirstName(String firstName) { 
     this.firstName = firstName; 
    } 

    public String getLastName() { 
     return lastName; 
    } 

    public void setLastName(String lastName) { 
     this.lastName = lastName; 
    } 

    @Override 
    public String toString() { 
     return "User (username = " + username + ", name = " + name + ")"; 
    } 
} 
+3

Зв Многое. Текст. – kolossus

+0

Вход должен быть '@ RequestScoped', и вы должны иметь управляемый bean-элемент' @ SessionScoped' для обработки пользовательских данных или даже обрабатывать его как атрибут сеанса. –

+0

@kolossus Ну, Java Security, IMO, возможно, является самой сложной Java EE, которая может охватить рассмотрение j_security_check vs Programmatic Security и настройку домена/области для вашего конкретного контейнера. Проблема в том, что если я не буду точно описывать свою проблему, кто-то собирается тратить свое время и свое время на предоставление ответа, который бесполезен для решения моей проблемы. –

ответ

1

Ваша проблема в том, как вы уже догадались,

if (userPrincipal != null) { 
      request.logout(); 
     } 

Вы воссоздании сеанс с вышеупомянутыми линиями. Не рекомендуется уничтожать сеанс в компоненте, включенном в сеанс. Это приводит к тому, что сеансовый бит очищается CDI.

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

@ApplicationScoped 
class LoginService{ 

public boolean login(String username,String password) { 
       String username = credentials.getUsername(); 
       String password = credentials.getPassword(); 
       Principal userPrincipal = request.getUserPrincipal(); 
       request.getUserPrincipal(); 
       if (userPrincipal != null) { 
        request.logout(); 
       } 
       boolean loggedIn = request.login(username,password); 
       if(loggedIn){ 
       users = new Users(); 
       users.setUsername(username); 
       session.setAttribute("Users",users);    
       } 
       return loggedIn; 
    } 

} 

Держите метод действия, чтобы войти в систему верительных

@RequestScoped 
    class Credential { 
      @Inject LoginService loginService; 
      String username; 
      String password; 

      login(ActionEvent action){ 
      if(loginService.login(username,password)) 
       //redirect to users 
      else 
       //show error 
      } 
    } 

Создать аннотацию, чтобы захватить зарегистрированного пользователя от КДИ

@Retention(RetentionPolicy.RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) 
public @interface SpringBean { 
    String value() default ""; 
} 

Используйте класс BeanLocator, чтобы произвести какой-либо объект, вы можете добавьте этот метод в LoginService, но лучше оставить его отдельным

public class BeanLocator {  
    @Produces @LoggedInUser 
    public Object getSessionAttribute(InjectionPoint ip){ 
     String beanName = ip.getAnnotated(). 
           getAnnotation(SessionAttribute.class).value(); 
     if(beanName==null || beanName.equals("")) 
      beanName = getDefaultBeanName(ip.getMember(). 
           getDeclaringClass().getName()); 
     return FacesContext.getCurrentInstance().getExternalContext(). 
        getSessionMap().get(beanName); 
    } 
    } 

использования его в других службах,

class MyOtherBean{ 
@Inject @@LoggedInUser Users; 
} 
+0

Еще раз приветствую, Авинаш. ОК. Хорошо иметь подтверждение, что я действительно уничтожаю/воссоздаю сеанс. Я читал во многих местах, что я должен установить Credentials как RequestScoped. Каждый пример, который я когда-либо видел, используя объект Credentials, всегда задает ему запрос, чтобы отклонить пароль пользователя. Разве я не хочу хранить учетные данные как RequestScoped? Я попробую, что вы говорите, но я просто не хочу открывать потенциальную дыру в безопасности. '@Produces @ LoggedIn' используется в других местах на других страницах, которые я не включил в свой пост. –

+0

Да, вы должны определенно хранить учетные данные в запросах, я не обратил на это внимания. Ваш Login также должен быть RequestScoped, однако вы можете сохранить компонент, подобный UserBean (или пользователям в вашем случае), чтобы сохранить данные пользователя в области сеанса. –

+0

O.K. Похоже, что внедрение затвердевает. Итак, последний вопрос, касающийся «UserBean» (или «Пользователи в вашем случае»): вводить или не вводить? Я бы подумал, что мне нужно вводить, в противном случае CDI будет игнорировать компонент '@ SessionScoped'. Однако, если я вставляю' @ Пользователи SessionScoped' будут подключаться к моему логическому элементу '@ RequestScoped' через CDI, который будет создавать сеанс каждый раз, когда кто-то посещает страницу входа/индекса. Думаю, я должен пойти с утилитой' @ RequestScoped', которая использует '@ Producer' метод для создания объекта Users, о котором я говорил с помощью @LuiggiMendoza? –

Смежные вопросы