自定义AuthenticationFailureHandler中的Flash属性

时间:2014-05-24 11:37:57

标签: spring authentication spring-security

登录失败时我想将用户重定向到错误页面并显示有意义的错误消息。是否可以添加将传递给后续请求的Flash属性?

下面提供的代码不起作用。 RequestContextUtils.getOutputFlashMap()会返回null

public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler
{
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException
    {
        FlashMap outputFlashMap = RequestContextUtils.getOutputFlashMap(request);
        if (outputFlashMap != null)
        {
            outputFlashMap.put("error", "Error message");
        }
        response.sendRedirect(request.getContextPath() + "/error");
    }
}

2 个答案:

答案 0 :(得分:2)

我在Spring 4.3.17中遇到了同样的问题,最后通过spring-webmvc代码找到了一个解决方案,并对如何在常规框架之外集成Flash属性进行了有根据的猜测。 SessionFlashMapManager是实现此目标的关键。我相信这个方法适用于Spring 3.1.1 +。

package org.myorg.spring.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.FlashMap;
import org.springframework.web.servlet.FlashMapManager;
import org.springframework.web.servlet.support.SessionFlashMapManager;

@Component
public final class FlashAuthenticationFailureHandler implements AuthenticationFailureHandler
{
    /**
     * Flash attribute name to save on redirect.
     */
    public static final String AUTHENTICATION_MESSAGE = "FLASH_AUTHENTICATION_MESSAGE";

    public FlashAuthenticationFailureHandler()
    {
        return;
    }

    @Override
    public void onAuthenticationFailure(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException exception) throws IOException, ServletException
    {
        if (exception != null)
        {
            final FlashMap flashMap = new FlashMap();
            // Don't send the AuthenticationException object itself because it has no default constructor and cannot be re-instantiated.
            flashMap.put(AUTHENTICATION_MESSAGE, exception.getMessage());
            final FlashMapManager flashMapManager = new SessionFlashMapManager();
            flashMapManager.saveOutputFlashMap(flashMap, request, response);
        }
        response.sendRedirect(request.getHeader("referer"));
        return;
    }
}

然后在需要flash属性的控制器中,只需添加一个名称相同的ModelAttribute:

@RequestMapping(value = {"/someview"}, method = RequestMethod.GET)
public String getSomePage(final Authentication authentication, @ModelAttribute(FlashAuthenticationFailureHandler.AUTHENTICATION_MESSAGE) final String authenticationMessage, final Model model) throws Exception
{
    if (authenticationMessage != null)
    {
        model.addAttribute("loginMessage", authenticationMessage);
    }

    return "myviewname";
}

然后可以在JSP中访问包含消息的页面属性,如下所示:

<c:if test="${not empty loginMessage}">
  <div class="alert alert-danger"><c:out value="${loginMessage}" /></div>
</c:if>

答案 1 :(得分:1)

我猜它是空的,因为你是从过滤器链调用函数,而flash映射是由Spring的DispatcherServlet维护的,此时请求还没有通过。

为什么不使用参数?即

 response.sendRedirect(request.getContextPath()+"/error?error=" + "Error Message");