Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
998 views
in Technique[技术] by (71.8m points)

jsf - Spring Security 4 and PrimeFaces 5 AJAX request handling

Good Day.

I've created a PrimeFaces 5 project (JSF 2.2) which makes use of Spring Security 4. I'm attempting to make use of p:dataTable control with single selection enabled, which through an ajax call, updates a p:pickList control.

The problem is related with Spring Security. If I deactivate the security of the page where my page controls are located (admin.faces), the ajax behavior works fine. But if I activate security, I get 403 status codes and the pickList doesn't get updated. I must indicate here that with security activated, if I attempt going to admin page, without logging first, I'm redirected to the login page.

This is the configuration used for Spring Security. Several code was eliminated for sake of simplicity:

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                    http://www.springframework.org/schema/security 
                    http://www.springframework.org/schema/security/spring-security.xsd">

    <http pattern="/*.css" security="none" />
    <http pattern="/*.js" security="none" />

    <http use-expressions="true">
        <intercept-url pattern="/login.faces" access="permitAll" />
        <intercept-url pattern="/javax.faces.resource/**" access="permitAll"/>
        <intercept-url pattern="/admin.faces" access="hasRole('Administrator')" />

        <form-login
            login-page="/login.faces"
            authentication-failure-url="/login.faces" />
        <logout />
    </http>

    <authentication-manager alias="authManager">
        <authentication-provider ref="daoAuthenticationProvider"/>
    </authentication-manager>
</beans:beans>

The login page:

<!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:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui">

<h:head>
    <title>Reports</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="_csrf" content="#{_csrf.token}"/>
    <meta name="_csrf_header" content="#{_csrf.headerName}"/>
    <link rel="stylesheet" type="text/css" href="stylesheet.css" />
</h:head>
<body>
    <h:messages />
    <h:form id="loginForm">
        <input type="hidden" name="#{_csrf.parameterName}" value="#{_csrf.token}"/>

        <p:panelGrid columns="2">
            <h:outputLabel value="User:" />
            <h:inputText value="#{loginBean.user}" required="true"/>

            <h:outputLabel value="Password:" />
            <h:inputSecret value="#{loginBean.password}" required="true"/>

            <f:facet name="footer">
                <div style="text-align:right;">
                    <h:commandButton type="submit" id="login"
                        action="#{loginBean.login}" value="Login" />
                </div>
            </f:facet>
        </p:panelGrid>
    </h:form>
</body>
</html>

The protected page (admin):

<!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:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui">

<h:head>
    <title>Reports</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="_csrf" content="#{_csrf.token}"/>
    <meta name="_csrf_header" content="#{_csrf.headerName}"/>
    <link rel="stylesheet" type="text/css" href="stylesheet.css" />
    <h:outputScript library="primefaces" name="jquery/jquery.js"/>
    <h:outputScript library="js" name="admin.js"/>
</h:head>
<body>
    <h1>Reports</h1>
    <br />

    <div>
        <h:form id="form">
            <input type="hidden" name="#{_csrf.parameterName}" value="#{_csrf.token}"/>

            <p:messages id="messages" showDetail="false" showSummary="true"
                autoUpdate="true" closable="true" />
            <br />

            <div style="float: left; width: 25%; margin-right: 10px;">
                <p:dataTable value="#{reports.tables}" var="tbl"
                    selection="#{reports.tablesel}" selectionMode="single"
                    rowKey="#{tbl}" scrollable="true" scrollHeight="300" id="tables">
                    <p:ajax event="rowSelect" update=":form:selColumns" />

                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="Tables" />
                        </f:facet>
                        <h:outputText value="#{tbl}" />
                    </p:column>
                </p:dataTable>
            </div>
            <div style="float: left;">
                <div style="margin-bottom: 10px;">
                    <div style="float: left; margin-right: 10px;">
                        <p:selectOneMenu value="#{reports.format}">
                            <f:selectItem itemValue="pdf" itemLabel="PDF" />
                            <f:selectItem itemValue="xls" itemLabel="Excel 2003" />
                        </p:selectOneMenu>
                    </div>
                    <div style="float: left; margin-right: 10px;">
                        <p:commandButton action="#{reports.create}"
                            value="View report" />
                    </div>
                    <div style="clear: both;"></div>
                </div>

                <p:pickList value="#{reports.lstColumns}" var="c"
                    itemLabel="#{c}" itemValue="#{c}" style="margin-bottom:10px;"
                    id="selColumns" />

                <div style="margin-bottom: 10px;">
                    <p:outputLabel value="Conditions" for="filter"
                        style="display:block;" />
                    <p:inputTextarea id="filter" value="#{reports.filter}"
                        style="width:97%;" />
                </div>

            </div>
        </h:form>
    </div>
</body>
</html>

A javascript file used in admin.faces:

$(document).ready(function() {
    var token = $("meta[name='_csrf']").attr("content");
    var header = $("meta[name='_csrf_header']").attr("content");
    $(document).ajaxSend(function(e, xhr, options) {
        xhr.setRequestHeader(header, token);
    })
});

Thanks for your attention.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I had the problem with 403 Responses for AJAX calls as well. The Problem was, that no CSRF Token was submitted.

By manually adding:

<h:form>
    ...
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</h:form>

it worked.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...