Webfilter登录机制总是需要两次尝试



我正在开发一种登录机制,可以在webfilter中对用户进行身份验证。当登录按钮被点击并且凭证有效时,它应该被重定向。

我遇到的问题是,Webfilter在第一次按下登录按钮后似乎没有凭据。日志记录提示参数不存在于应该存储凭据的@SessionScoped bean中。

要真正登录,我必须再次按下登录按钮(这一次我是否输入凭据并不重要),然后我被重定向。

当我尝试使会话无效时也会出现同样的问题。我在页面上,单击按钮使其失效,页面再次显示,只有在刷新后我才被重定向到登录页面。

在会话无效的情况下,验证用户和重定向的整个过程在webfilter中进行。

我认为问题是,参数和其他动作只有在webfilter被处理后才生效,但是,这些机制应该如何工作?我到处读到,自实现的登录机制应该在webfilter中实现,这样做非常有意义。

编辑:我已经添加了必要的代码。(不是全部,但相当多)

login.xhtml

<h:body>
<h1>Login</h1>
<h:form id="loginForm">
    <h:message for="loginForm" />
    <h:outputLabel value="Username" />
    <h:inputText value="#{CRMSession.username}"></h:inputText>
    <br />
    <h:outputLabel value="Passwort" />
    <h:inputSecret value="#{CRMSession.passHash}"></h:inputSecret>
    <h:commandButton action="submit" value="submit"></h:commandButton>
</h:form>

Webfilter(缩短):(我拿出了整个cookie部分,因为这是所有的注释掉了,目前的错误不能在那里。我只是把它拿出来让整个东西更容易读)

@WebFilter(filterName = "SP", urlPatterns = "/*")
public class SessionProvider implements Filter {
private final static String AUTH_COOKIENAME = "kimcrmstoken";
private final static String LOGINURL = "./login.jsf";
private final static String INDEXURL = "./index.jsf";
@Inject
CRMSession crmsession;
@Inject
LoggingProvider loggingProvider;
@Inject
LoginHandler loginHandler;
@Inject
ConfigUpdates configUpdates;
@Inject
CRMContext context;
@Inject
UserHandler userHandler;
Logger logger;
@Override
public void destroy() {
    // TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse resp = (HttpServletResponse) response;
    Cookie[] cookies = req.getCookies();
    logger = loggingProvider.getLogger(this.getClass().getName());
    logger.log(LogLevel.INFO, "SessionProvider working");

    if(credentialsPresent())
        logger.log(LogLevel.INFO, "credentials present");
    else
        logger.log(LogLevel.INFO, "NO credentials present");
    if(crmsession.isAuthenticated())
        logger.log(LogLevel.INFO, "Session authenticated");
    if (!crmsession.isAuthenticated() && credentialsPresent()) {
        /*
         * Session ist nicht authentifiziert, aber credentials sind
         * vorhanden
         */
        logger.log(LogLevel.INFO, "session not authenticated but credentials present");
        try {
            if (!loginHandler.validateCredentials()) {
                logger.log(LogLevel.INFO, "Credentials invalit");
                crmsession.setPassHashToNull();
                crmsession.setAuthenticated(false);
                resp.sendRedirect(LOGINURL);
            } else {
                logger.log(LogLevel.INFO, "Credentials valid");
                crmsession.setAuthenticated(true);
                crmsession.setLoggedIn(true);
                crmsession.setJustloggedin(true);
            }
        } catch (SQLException e) {
            // wird erreicht wenn bei der Userauthentifizierung eine
            // SQLexception geworfen wird
            logger.log(LogLevel.ALERT, "Fehler in User Authentifizierung");
            throw new ServletException(e.getMessage());
        }
    }


    /*
     * prüfen ob in der Session ein username und ein Passwort vorhanden
     * sind, wenn nicht->loginpage
     */
    if (!crmsession.isAuthenticated()) {
        if (req.getRequestURI().contains("/login.jsf")) {
            logger.log(LogLevel.INFO, "PATH is login.jsf");
            crmsession.setAuthenticated(false);
            chain.doFilter(request, response);
            return;
        }
        if (!credentialsPresent()) {
            logger.log(LogLevel.INFO, "NO Pass or username, redirecting");
            crmsession.setAuthenticated(false);
            resp.sendRedirect(LOGINURL);
            return;
        }
    }

    }
    /*
     * Weiterleitung zum index nach der anmeldung
     */
    if(crmsession.isAuthenticated() && crmsession.isJustloggedin()){
        crmsession.setJustloggedin(false);
        resp.sendRedirect(INDEXURL);
    }
    // Fortfahren
    logger.log(LogLevel.FINEST, "SessionProvider done");
    chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
    // TODO Auto-generated method stub
}
public boolean credentialsPresent() {
    if (crmsession.getUsername() == null)
        return false;
    if (crmsession.getPassHash() == null)
        return false;
    if (crmsession.getUsername().equals(""))
        return false;
    if (crmsession.getPassHash().equals(""))
        return false;
    return true;
}

}

会话无效同样的问题:

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

index
<h:form>
    <h:commandButton action="#{index.clearSession}" value="clear">
</h:commandButton>
</h:form>
</html>

支持Bean:

import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.http.HttpSession;
@RequestScoped
@Named
public class Index implements Serializable {
public String clearSession(){
    HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
    session.invalidate();
    return "./index.jsf";
}
}

看来你把过滤器的职责搞错了。它的职责不是执行实际的登录(或注销)。它的职责是根据登录的用户限制对所请求资源的访问。

您应该在与登录表单关联的请求/视图作用域支持bean的操作方法中执行实际的登录(和注销)。成功登录/注销后,您应该重定向到目标页面。过滤器应该检查当前登录的用户是否被允许访问所请求的资源。如果是,则继续过滤链。如果不是,则重定向到登录页面或发送401/403。

注意,您的过滤器不包括JSF资源或ajax请求。在这个答案中,您可以找到一个JSF感知身份验证过滤器的完整示例:会话到期时的授权重定向在提交JSF表单时不起作用,页面保持不变。

相关内容

  • 没有找到相关文章

最新更新