如何组合令牌认证和CRSF?

时间:2017-02-27 10:10:27

标签: spring rest jsf

我正在开发一个包含以下内容的Web应用程序

  • Rest Web服务(Spring 4)| JWT令牌认证
  • 网页(login.xhtml,index.xhtml)(JSF,primeface)| CRSF

我现在面临的问题很奇怪。

如果启用了Spring安全性,则在授予访问权限之前,需要对对其余Web服务的任何访问进行身份验证。我正在使用JWT令牌身份验证登录。但是,登录后我的网页会失败。即我的登录成功,但此后的任何操作都会产生invalid crsf token or null request error.

如果我的Spring安全性被禁用,我的休息服务不需要进行身份验证即可访问Web服务,但我的网页运行正常。

如何将两种解决方案整合在一起?

我的所有网页都包含以下内容:

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

的ApplicationContext-security.xml文件:

<http pattern="/auth/login" security="none" />
    <http pattern="/login.xhtml" security="none" />
    <http pattern="/index.xhtml" security="none" />
    <http pattern="/javax.faces.resource/**" security="none" />
    <http pattern="/RES_NOT_FOUND" security="none" />
    <http pattern="/img/**" security="none" />

    <sec:http auto-config="false" create-session="stateless" entry-point-ref="customEntryPoint" use-expressions="true">
        <intercept-url pattern="/admin/**"          access="hasRole('ADMIN') or hasRole('HQ')" />
        <intercept-url pattern="/audit/**"          access="hasRole('ADMIN')" />
        <intercept-url pattern="/request/**"        access="hasRole('ADMIN') or hasRole('HQ')" />
        <intercept-url pattern="/reporting/**"      access="hasRole('ADMIN') or hasRole('HQ')" />

        <sec:custom-filter ref="customAuthenticationFilter"
            before="PRE_AUTH_FILTER" />

<!--        <sec:csrf disabled="true" /> -->
    </sec:http>

正如您所见,我包含<http pattern="/index.xhtml" security="none" />,以便我可以允许我的index.xhtml中的哪些功能正常工作。但现在我可以直接访问index.xhtml。

有人可以就如何解决这个问题提出建议吗?

=====已编辑。更多信息=====

要添加,这是我的登录页面和控制器。

login.xhtml:

<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

<h:head>
    <title>BTS Upload</title>
    <h:outputStylesheet library="css" name="bootstrap.min.css" />
    <h:outputScript library="js" name="jquery-1.11.1.min.js" />
    <h:outputScript library="js" name="bootstrap.min.js" />
</h:head>

<!-- Css here -->

<h:body>
    <font color="red"> <h:outputLabel
            value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
    </font>

    <div class="container">
        <div class="row">
            <div class="col-sm-6 col-md-4 col-md-offset-4">
                <h1 class="text-center login-title">Sign in</h1>
                <div class="account-wall">

                    <h:graphicImage class="profile-img" library="images"
                        name="photo.png" />

                    <h:form class="form-signin">
                        <h:outputLabel value="Enter UserName:" />

                        <h:inputText id="username" value="#{loginAction.username}"
                            required="true" requiredMessage="Please enter your username"
                            autofocus="true" class="form-control"></h:inputText>

                        <h:message for="username" id="msg"
                            errorStyle="color:red; display:block" />

                        <br />
                        <h:outputLabel value="Enter Password:" />
                        <h:inputSecret id="password" value="#{loginAction.pwd}"
                            required="true" requiredMessage="Please enter your password"
                            class="form-control"></h:inputSecret>

                        <h:message for="password" id="msg1"
                            errorStyle="color:red; display:block" />

                        <br />
                        <br />

                        <h:commandButton class="btn btn-lg btn-primary btn-block"
                            action="#{loginAction.login}"
                            value="Login"></h:commandButton>

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

                    </h:form>
                </div>

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

控制器:

@ManagedBean(name="loginAction")
@SessionScoped
public class LoginAction extends BaseAction implements Serializable
{
    private static final long serialVersionUID = 1094801825228386363L;

    private String pwd;
    private String msg;
    private String username;

    @ManagedProperty("#{accessControlService}")
    private AccessControlService accessControlService;

    public String getPwd()
    {
        return pwd;
    }

    public void setPwd(String pwd)
    {
        this.pwd = pwd;
    }

    public String getMsg()
    {
        return msg;
    }

    public void setMsg(String msg)
    {
        this.msg = msg;
    }

    public String getUsername()
    {
        return username;
    }

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

    //validate login and redirect to the specified website.
    public String login()
    {

        System.out.println();
        System.out.println("Call Log in");

        if (username.equals("") || pwd.equals(""))
        {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
                    "Incorrect Username and Password", "Please enter correct username and Password"));
            return "login";
        }

        boolean valid = false;
        String token = "";

        try
        {
            token = accessControlService.isAuthorizedUser(username, pwd, PropertiesUtil.LoginType.WEB_BTS.ordinal(), this.getRequest());
        }
        catch (Exception e)
        {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
                    "Error", e.getLocalizedMessage()));
        }

        if(token.contains(PropertiesUtil.TOKEN_HEADER))
        {
            valid = true;
        }

        if (valid)
        {
            HttpSession session = this.getSession();
            session.setAttribute("username", username);
            session.setAttribute("token", token);

            return "admin";
        }
        else
        {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
                    "Incorrect Username and Password", "Please enter correct username and Password"));
            return "login";
        }
    }

    // logout event, invalidate session
    public String logout()
    {
        System.out.println("**********************************************************");
        try
        {
            accessControlService.logout(getUsername(), PropertiesUtil.LoginType.WEB_BTS.ordinal(), getRequest());
            HttpSession session = this.getSession();
            session.invalidate();
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return "login";
    }

    public AccessControlService getAccessControlService()
    {
        return accessControlService;
    }

    public void setAccessControlService(AccessControlService accessControlService)
    {
        this.accessControlService = accessControlService;
    }
}

1 个答案:

答案 0 :(得分:0)

首先,您必须确保具有spring security 4 compatible * -security.xml和* -servlet.xml look at this

从您发布的security.xml的一部分,我可以看到您没有form-login标记。它应该是这样的

<security:form-login default-target-url="/index"
                         login-page="/login"
                         username-parameter="j_username"
                         password-parameter="j_password"
                         login-processing-url="/j_spring_security_check"
                         authentication-failure-url="/login?login_error=1"/>

你的登录jsp需要有动作j_spring_security_check来触发过滤链:

<form action="<c:url value="/j_spring_security_check"/>" method="POST"> ... 

您不需要csrf隐藏输入,因为Spring会自动将其注入请求标头和参数(如果您不禁用它),从第4季开始