【问题标题】:Spring Security 4 intercept anonymous user AccessDeniedExceptionSpring Security 4 拦截匿名用户 AccessDeniedException
【发布时间】:2016-03-08 23:23:09
【问题描述】:

我的网站允许未经身份验证(匿名)的用户搜索需要身份验证才能查看的内容。目前,当他们单击链接以查看搜索结果页面上内容项之一的详细信息时,Spring Security 正确地将用户识别为未经身份验证并显示登录页面。但是,我想干预并改为显示一个页面来鼓励匿名用户注册该网站。我已经追踪了过滤器链中发生的事情,但我不清楚是否应该扩展现有过滤器或处理程序或创建自定义过滤器或处理程序。如果是后者,我不确定它应该去哪里。

当我通过调试运行它时,我可以看到以下情况发生:

  • ExceptionTranslationFilter.doFilter 执行 FilterSecurityInterceptor 确定详细信息页面需要身份验证(返回 -1 投票并抛出 AccessDeniedException)
  • ExceptionTranslationFilter 捕获异常,确定用户是匿名用户并调用authenticationEntryPoint,在本例中为LoginUrlAuthenticationEntryPoint
  • LoginUrlAuthenticationEntryPoint 调用 DefaultRedirectStrategy 重定向到登录页面

所以,对于这个用例,基本上我需要覆盖到登录页面的重定向。我最好的猜测是创建一个自定义过滤器,检查访问此特定详细信息页面的匿名用户的组合,并强制重定向到加入页面,将过滤器插入到ExceptionTranslationFilter 之后的链中。或者这对于处理单页重定向来说是不是有点矫枉过正,而有更简单的方法可以做到这一点?

【问题讨论】:

  • 不,创建并注入一个自定义的AuthenticationEntryPoint,它决定重定向到哪个页面而不是默认登录页面。不要破解过滤器,只需创建一个适当的入口点。
  • @M.Deinum 感谢您的提示-效果很好!唯一的副作用是,如果网站成员尚未登录,他们将看到加入页面,但这实际上没问题,因为页面上的措辞涵盖了这种情况。

标签: spring-security


【解决方案1】:

对于任何感兴趣的人,这里是自定义身份验证入口点的代码,借用自 LoginUrlAuthenticationEntryPoint 和 ExceptionTranslationFilter。

public class CustomAuthLoginEntryPoint extends LoginUrlAuthenticationEntryPoint {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private PortResolver portResolver = new PortResolverImpl();
    private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
    private RequestCache requestCache = new HttpSessionRequestCache();
    private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    private String joinPageUrl;

    public CustomAuthLoginEntryPoint(String loginFormUrl) {
        super(loginFormUrl);
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException, ServletException {
        logger.debug("commence");

        String redirectUrl = null;

        if (!StringUtils.isBlank(joinPageUrl)) {
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            if (auth == null || trustResolver.isAnonymous(auth)) {
                SavedRequest savedRequest = requestCache.getRequest(request, response);
                redirectUrl = savedRequest.getRedirectUrl();

                if (redirectUrl.indexOf("viewDetail") > 0) {
                    String joinPageUrl = buildRedirectUrlToJoinPage(request);
                    logger.debug("Redirecting to '" + joinPageUrl + "'");
                    redirectStrategy.sendRedirect(request, response, joinPageUrl);
                    return;
                }               
            }
        }

        super.commence(request, response, authException);
    }

    protected String buildRedirectUrlToJoinPage(HttpServletRequest request) {

        int serverPort = portResolver.getServerPort(request);
        String scheme = request.getScheme();

        RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();

        urlBuilder.setScheme(scheme);
        urlBuilder.setServerName(request.getServerName());
        urlBuilder.setPort(serverPort);
        urlBuilder.setContextPath(request.getContextPath());
        urlBuilder.setPathInfo(joinPageUrl);

        return urlBuilder.getUrl();
    }

    public void setJoinPage(String joinPageUrl) {
        this.joinPageUrl = joinPageUrl;
    }
}

我将此添加到我的WebSecurityConfigurerAdapter:

@Bean
public CustomAuthLoginEntryPoint customAuthLoginEntryPoint() {
    CustomAuthLoginEntryPoint entryPoint = new CustomAuthLoginEntryPoint("/user/login");
    entryPoint.setJoinPage("/user/join");
    return entryPoint;
}

和http配置:

    .exceptionHandling()
        .accessDeniedHandler(accessDeniedHandler())
        .authenticationEntryPoint(customAuthLoginEntryPoint())

【讨论】:

    猜你喜欢
    • 2014-11-24
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 1970-01-01
    • 2020-08-19
    • 2012-08-15
    • 2014-06-17
    • 2013-03-17
    相关资源
    最近更新 更多