【问题标题】:JSF - Primefaces - how to intercept p:menuitem outcomeJSF - Primefaces - 如何拦截 p:menuitem 结果
【发布时间】:2013-12-29 10:45:14
【问题描述】:

我正在尝试使用自定义 ActionListener 拦截 p:menuitem 结果,但我不能。看来,如果我将结果更改为行动,它会起作用(当然),但我无法使这些链接中的 f:param 起作用。

拦截 p:menuitem 结果的正确方法是什么?

更新:这是我目前的方法/想法。对我来说听起来很麻烦,但可能会奏效。虽然,欢迎使用更好的方法来实现这一点 -

我正在考虑使用过滤器,就像 BalusC 在这里描述的那样

How could I read a JSF session bean from a filter?

我最初的想法是拦截任何请求(不仅仅是操作请求)并对其应用一些安全规则。

我做了一些研究,似乎 JSF 应用程序有很多安全模型,有些会受 bean 方法限制,有些会受 URL 限制,但就我而言,我想要一些可以通过 xhtml 控制的东西。

所以我打算这样做 - http://www.kianworknotes.com/2013/06/authorization-in-jsf-with-facelets-view.html

我希望我的应用让用户为每个 xhtml 应用权限规则,所以我正在考虑这个想法

我可以这样列出所有的xhtml

ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
List<String> pages = getResources("/private", ".xhtml");
for (String page : pages) {
    try {
        System.out.println(page);
        System.out.println(getMetaData(context.getResourceAsStream(page)));
    } catch (Exception e) {
        e.printStackTrace();
    }
}
return pages;

在哪里

private List<String> getResources(String path, String suffix) {
    ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
    Set<String> resources = context.getResourcePaths(path);
    List<String> filteredResources = new ArrayList<String>();
    for (String resource : resources) {
        if (resource.endsWith(suffix)) {
            filteredResources.add(resource);
        } else if (resource.endsWith("/")) {
            filteredResources.addAll(getResources(resource, suffix));
        }
    }
    return filteredResources;
}

(上面的代码从这里借用 - https://community.jboss.org/thread/189427

每个 xhtml 在 [h:head] 中都有自己的元标记,例如 [meta name="module" content="Security"]

我可以使用 SAX 解析器解析每个 xhtml 以提取此信息

private class MyDefaultHandler extends DefaultHandler{
    private String titleName = null;
    private boolean skip = false;

    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        if (!skip && qName.equalsIgnoreCase("meta")) {
            boolean isThis = false;

            for (int i = 0; i < attributes.getLength(); i++) {

                String attributeName = attributes.getLocalName(i);
                String attributeValue = attributes.getValue(i);
                System.out.println("found attribute with localname=" + attributeName + " and value=" + attributeValue);

                if (attributeName.equals("name") && attributeValue.equals("module")){
                    titleName = attributes.getValue(i);
                    isThis = true;
                    break;
                }
            }

            if (isThis){
                for (int i = 0; i < attributes.getLength(); i++) {
                    String attributeName = attributes.getLocalName(i);
                    String attributeValue = attributes.getValue(i);

                    if (attributeName.equals("content")){
                        titleName = attributeValue;
                        skip = true;
                        break;
                    }
                }
            }
        }
    }

    public String getTitleName(){
        return titleName;
    }
}

public String parseTitle(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException {

    XMLReader reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();

    //if you comment the line below, your parser will take 1 minute EACH XML
    reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

    MyDefaultHandler handler = new MyDefaultHandler();
    reader.setContentHandler(handler);
    InputSource inputSource = new InputSource(new BufferedInputStream(inputStream));
    reader.parse(inputSource);

    return handler.getTitleName();
}

最后,我可以按照 BallusC 的建议从过滤器中获取一些 sessionScoped 托管 bean

public void doFilter(ServletRequest arg0, ServletResponse arg1,
        FilterChain arg2) throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) arg0;
    HttpServletResponse response = (HttpServletResponse) arg1;
    HttpSession session = ((HttpServletRequest) request).getSession();
    Enumeration<String> names = session.getAttributeNames();
    while(names.hasMoreElements()){
        System.out.println(names.nextElement());
    }
    AuthorizationManagerMB authorizationManagerMB = (AuthorizationManagerMB)session.getAttribute("authorizationManagerMB");
    if (authorizationManagerMB == null){
        System.out.println("Filter = not logged");
    }else{
        System.out.println("Filtering = "+request.getRequestURI());
        authorizationManagerMB.doSomething();
    }

这很麻烦 :-) 我知道

但我可以通过 xhtml 管理访问,即使用户在浏览器中提供了直接 URL,无论是否使用 ajax

如果有人知道一种不那么繁琐且更优雅的方法,允许用户动态配置角色,那将是受欢迎的:-)

ps。有趣的是,JSF 使用 xhtml 的方法如此之少。你不能列出,你不能添加元数据,你不能检索元数据。它以 bean 为中心 :-)

【问题讨论】:

  • 对于安全问题,使用过滤器是可行的方法,因为它是 http 请求生命周期的开始。我还使用 preRenderView 事件为 GET 请求添加了特定限制。除此之外,控制用户是否有权执行操作是控制层的问题。您应该在那里实施一些安全措施,以提供来自不同点(web-http、web 服务、rmi..)的安全访问

标签: jsf primefaces actionlistener menuitem


【解决方案1】:

outcome 生成一个简单的 GET 请求,可以带参数使用,不需要用表单包围。为了在服务器端执行一些逻辑,您首先需要一个 POST。

对于您的具体情况,最佳选择是使用 action 方法,让您在导航到新视图之前执行操作。随心所欲地返回与目标视图匹配的导航结果:

<p:menuitem action="#{bean.changePage(param)}" />
public String changePage(String param){
    //Do some stuff
    return "page2?faces-redirect=true&includeViewParams=true&p1="+param;
}

此外,您必须在目标视图中捕获该参数并设置到您的 bean 中:

<f:metadata>
    <f:viewParam name="p1" value="#{destinationBean.param}" />
</f:metadata>

【讨论】:

  • 谢谢。无论如何,我一直在寻找类似这种方法的东西 - stackoverflow.com/questions/10985528/… - 请注意,尽管问题说“没有过滤器”,但似乎我无法避免使用它来拦截请求
  • 其他选择是直接在destinationBean 中执行您想要的操作。由于您的问题太宽泛,我无法预测您具体在寻找什么。
猜你喜欢
  • 1970-01-01
  • 2016-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多