JSF创建用于安全管理的托管bean(应用程序范围)

JSF创建用于安全管理的托管bean(应用程序范围),jsf,javabeans,code-injection,managed,Jsf,Javabeans,Code Injection,Managed,我在创建自定义安全筛选器时遇到问题。 我打算创建一个过滤器,用于与服务器检查URL中传递的sessionId,以进行身份验证和授权。 我打算使用代码中已经存在的现有JSF框架(如会话缓存等) 为此,我首先定义一个应用程序范围的bean。faces-config.xml如下所示: 安全豆 com.ecom.scarer.security.SecurityBean 应用程序 登录 #{loginBD} 然后将名为SecurityBean的类定义为: public class SecurityB

我在创建自定义安全筛选器时遇到问题。 我打算创建一个过滤器,用于与服务器检查URL中传递的sessionId,以进行身份验证和授权。 我打算使用代码中已经存在的现有JSF框架(如会话缓存等)

为此,我首先定义一个应用程序范围的bean。faces-config.xml如下所示:


安全豆 com.ecom.scarer.security.SecurityBean 应用程序
登录 #{loginBD}

然后将名为SecurityBean的类定义为:

public class SecurityBean implements Serializable {


// attributes
private LoginBD loginBD;    

public void setLoginBD(LoginBD loginBD) {
this.loginBD = loginBD;
}


public UserSession getUserSessionById(String sessionId) throws InvalidSessionException{             

// get the session id
UserSession us = loginBD.getSession(sessionId);

return us;
}

}
我有一个过滤器:

public class SecurityFilter implements Filter{

private ServletContext servletContext;

// --------------- overridden method for Filter interface --------------- 

public void init(FilterConfig filterConfig) throws ServletException {
    servletContext = filterConfig.getServletContext(); 
}

public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {

    Map<String, String[]> paramMap = request.getParameterMap();

    FacesContext facesContext = getFacesContext(request, response);

    // get the application bean for security         
    SecurityBean sb = (SecurityBean)getApplicationBean("securityBean", facesContext);

    // values needed from the parameter
    String[] vals = paramMap.get("accountId");
    String accId = (vals != null && vals.length > 0)? vals[0] : null;
    System.out.println("Account id .................. = " +  accId);

    String[] sessionIds = paramMap.get("sessionId");
    String sessionId = (sessionIds != null && sessionIds.length > 0)? sessionIds[0] : null;

    System.out.println("The session ...................... = " + sessionId);

    try {

        UserSession us = sb.getUserSessionById(sessionId);
    } catch (InvalidSessionException e) {
        System.out.println("Invalid session exception ");
        e.printStackTrace();
    }

    chain.doFilter(request, response);              
}

public void destroy() {
    // do nothing       
}


// --------------- for fetching the FacesContext


// You need an inner class to be able to call FacesContext.setCurrentInstance
// since it's a protected method
private abstract static class InnerFacesContext extends FacesContext {
    protected static void setFacesContextAsCurrentInstance(FacesContext facesContext) {
        FacesContext.setCurrentInstance(facesContext);
    }
}   


private FacesContext getFacesContext(ServletRequest request, ServletResponse response) {
    // Try to get it first  
    FacesContext facesContext = FacesContext.getCurrentInstance();
    if (facesContext != null) return facesContext;

    FacesContextFactory contextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
    LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);    
    Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);

    // Either set a private member servletContext = filterConfig.getServletContext(); 
    // in you filter init() method or set it here like this:
    // ServletContext servletContext = ((HttpServletRequest)request).getSession().getServletContext();
    // Note that the above line would fail if you are using any other protocol than http

    // Doesn't set this instance as the current instance of FacesContext.getCurrentInstance 
    facesContext = contextFactory.getFacesContext(servletContext, request, response, lifecycle);

    // Set using our inner class
    InnerFacesContext.setFacesContextAsCurrentInstance(facesContext);

    // set a new viewRoot, otherwise context.getViewRoot returns null
    UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, "yourOwnID");
    facesContext.setViewRoot(view);

    return facesContext;
}   


/**
 * 
 * The method fetches the application bean for the given bean name.
 * The object returned should be cast correctly to the bean
 * 
 * @param beanName - the name of bean as described in JSF config
 * @return - The bean as object. It should be cast to correct bean object before using
 */     
private Object getApplicationBean(String beanName, FacesContext fContext) {     
    Object bean = fContext.getExternalContext().getApplicationMap().get(beanName);      
    return bean;
}   
}

如何获取loginBD属性(在faces config中定义为属性)的句柄?有没有办法手动(通过代码)注入这个属性?或者用其他方法来处理这件事

这不是在servlet过滤器中获取应用程序范围的托管bean的正确方法。您无需手动为其创建整个
FacesContext
。应用程序范围的托管bean存储为servletcontext属性,托管bean名称作为键

因此,在
doFilter()
方法中,只需执行以下操作:

ServletContext context = request.getServletContext();
SecurityBean securityBean = (SecurityBean) context.getAttribute("securityBean");
// ...
至于您的具体问题,在JSF首次初始化之前,您似乎需要这个bean。在这种情况下,当它为
null
时,您确实需要自己创建它

if (securityBean == null) {
    securityBean = new SecurityBean();
    securityBean.setLoginBD(new LoginBD()); // Or get it from application scope?
    context.setAttribute("securityBean", securityBean);
}

// ...


与具体问题无关,我对这种设计方法打了很多问号。但由于具体的功能需求不明确,我无法提出正确的方法。至少,您似乎正在重新发明容器管理的身份验证和/或
HttpSession
、会话范围的托管bean、EJB等已经提供的功能。这是不对的。这是不必要的过度复杂。

嗨,巴卢斯,谢谢你的快速回复。当用户登录时,我们创建sessionid并将它们与其他用户信息一起存储在缓存中(以及数据库中)。当用户现在导航到页面时,所有链接的URL中都会有sessionId,该ID将被检查是否过期以及是否有授权。我打算使用现有的会话缓存(由loginBD访问),它是一个Spring组件。我的问题是,当我将这个bean设置为应用程序作用域且eager=true时,我就无法获得loginBD的句柄。我已经按照您的建议更正了代码。除了上面提到的,我还添加了行securityBean.setLoginBD(newLoginBD());根据你的评论。但是loginBD本身使用自动连接和Spring注释来获取Dao值。因此,它们稍后在loginBD中提供空指针。在加载Spring组件之前,是否有延迟应用程序范围bean初始化的方法?我使用Glassfish服务器。
if (securityBean == null) {
    securityBean = new SecurityBean();
    securityBean.setLoginBD(new LoginBD()); // Or get it from application scope?
    context.setAttribute("securityBean", securityBean);
}

// ...