Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/jsf/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在使用JSF2.0、CDI、EJB3.1ServletSpec3.0编程安全性时设置UserBean_Jsf_Jakarta Ee_Jsf 2_Java Ee 6_Cdi - Fatal编程技术网

如何在使用JSF2.0、CDI、EJB3.1ServletSpec3.0编程安全性时设置UserBean

如何在使用JSF2.0、CDI、EJB3.1ServletSpec3.0编程安全性时设置UserBean,jsf,jakarta-ee,jsf-2,java-ee-6,cdi,Jsf,Jakarta Ee,Jsf 2,Java Ee 6,Cdi,这是一个后续问题 登录后,我的应用程序需要使用request.login()查询容器以进行身份验证,然后设置一个“用户”bean,其中包含用户名、密码、角色和特定于位置的字段。成功对容器(WAS 8)进行授权后,需要检查用户的角色,以确定用户应重定向到的适当欢迎页面。我的容器实现了一个联邦存储库,它基本上将3个LDAP分支、一个数据库和一个平面文件集中在一起。有很多角色(现在5个,以后可能会更多) 我有两个bean:一个请求范围的凭据bean和一个名为Login的会话范围bean。Login包含

这是一个后续问题

登录后,我的应用程序需要使用request.login()查询容器以进行身份验证,然后设置一个“用户”bean,其中包含用户名、密码、角色和特定于位置的字段。成功对容器(WAS 8)进行授权后,需要检查用户的角色,以确定用户应重定向到的适当欢迎页面。我的容器实现了一个联邦存储库,它基本上将3个LDAP分支、一个数据库和一个平面文件集中在一起。有很多角色(现在5个,以后可能会更多)

我有两个bean:一个请求范围的凭据bean和一个名为Login的会话范围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未存储在会话中

我已经删除了第一段代码,并注意到我的用户bean的信息随后存储在会话中,可以在后续的用户页面上查看。我逐行重新介绍了第一段代码,并注意到:

if (userPrincipal != null) {
    request.logout();
}
导致问题的原因

我该如何存储实现编程安全性和JSF2.0/CDI的用户bean?我已经花了好几个星期在这上面了。我可以想象实现一些更复杂的东西,比如一个过滤器,它捕获重定向,抓取userprincipal,调用db或ldap以获取其他属性,然后重定向到适当的页面……但我希望保持简单。必须有一个简单的方法来做到这一点

我最初尝试使用j_security_check登录,并在web.xml中指定表单。现在,使用一个JSF2.0表单和一个登录方法,我注意到表单被忽略了,取而代之的是BASIC。System.out.println(“getAuthType?。”+request.getAuthType());在login方法中返回“BASIC”。这会导致讨厌的缓存,这就是为什么需要request.logout。否则,request.login将失败

我昨晚无意中发现了一个链接,其中包含到。因此,可能有一种方法可以获取userprincipal,设置用户bean,并重定向到适当的欢迎页面。我不知道第二个链接有多过时。此外,j_security_check似乎不能与一种编程方法结合使用,以根据角色确定我应该将用户重定向到哪个页面

至于我应该使用j_security_check还是programming security/JSF/CDI,我只需要找出一个简单的方法,允许我在会话中存储登录bean或独立用户bean

这是我的视图中的登录表单:

<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>
以下是我的凭据bean:

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页面(仅用于验证会话信息的测试目的):


你的问题就像你猜的那样

 if (userPrincipal != null) {
            request.logout();
        }
您正在使用上述行重新创建会话。在会话作用域bean中销毁会话不是一个好主意。这导致会话bean被CDI清理

在清理会话bean的操作方法时,需要存储用户名、密码

@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
          }
    }
创建注释以从CDI抓取登录用户

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

登录名应该是
@RequestScoped
,您应该有另一个
@SessionScoped
托管bean来处理用户数据,甚至将其作为会话属性处理。@kolossus Well,Java Security,IMO,考虑到j_安全检查与编程安全性以及为特定容器设置域/领域,可能是最难掌握的JavaEE主题。问题是,如果我不能准确地描述我的问题,有人会浪费他们的时间和我的时间来提供一个对解决我的问题毫无价值的答案。@Luigimendoza-我应该如何访问这个新的SessionScoped bean?我不能将其注入RequestScope登录bean,因为这将导致在构造时创建会话对象。我想我必须将user/userprincipal存储在会话映射中,根据角色重定向到适当的页面,然后将一个会话bean(通过会话映射的user/userprincipal填充其字段)注入到一个RequestScoped bean?@luigimendoza-对于您提到的会话属性方法,我曾经在会话映射的某一点上放置一个用户对象。不过我觉得这有点傻。我想我可以创建一个SessionUtil类,它有一个从会话映射返回用户属性/对象的Producer方法。我认为将用户数据存储为会话属性没有问题,但是如果可以的话,可以使用
@SessionScoped
方法。是的,您可以使用实用程序类访问会话数据(不一定仅限于此用户属性)。好的,很高兴确认我确实在破坏/重新创建会话。我在很多地方读过,我应该将凭据设置为RequestScope。我见过的每一个使用Credentials对象的示例都会将其设置为request,以便拒绝用户的密码。我不想将凭据保留为RequestScope吗?我会试试你说的,但我只是不想打开一个潜在的安全漏洞
@products@LoggedIn
在我的帖子中没有包含的其他页面上使用。是的,你应该明确地保持credentials RequestScope,我忽略了它。您的登录名也应该是RequestScope,但是您可以保留一个类似于UserBean的bean(或者您案例中的用户),以便在会话范围中保留用户详细信息。好的。这听起来像是一个正在固化的实现。所以,关于“UserBean(或您案例中的用户)”的最后一个问题是:注入还是不注入
@Retention(RetentionPolicy.RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface SpringBean {
    String value() default "";
}
    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;
}