java - PreAuthenticatedAuthenticationProvider UsernameNotFound 异常返回 401 而不是拒绝页面

标签 java spring spring-security

我使用 spring 4.1.6.RELEASE 和 spring-security 4.0.1.RELEASE。

有RequestHeaderAuthenticationFilter和PreAuthenticatedAuthenticationProvider。如果用户服务抛出 UsernameNotFoundException,我希望我的应用程序显示“拒绝”页面。 实际上,应用程序显示基本的 HTTP 授权表单(简单的浏览器弹出凭据),并在取消时提供 401 响应。

这是我的配置:

<s:http auto-config="true" use-expressions="true">
    <s:intercept-url pattern="/report/**" access="hasRole('ROLE_USER')"/>
    <s:csrf disabled="true"/>
    <s:custom-filter ref="preAuthFilter" position="PRE_AUTH_FILTER"/>
    <s:form-login
            authentication-failure-url="/denied.jsp"/>
</s:http>

<b:bean id="preAuthFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
    <b:property name="principalRequestHeader" value="REMOTE_USER"/>
    <b:property name="authenticationManager" ref="authManager"/>
</b:bean>

<s:authentication-manager id="authManager">
    <s:authentication-provider user-service-ref="userDetailsService"/>
</s:authentication-manager>

<b:bean id="userDetailsService" class="com.db.dump.tool.security.UserDetailsServiceImpl"/>

类 UserDetailsS​​erviceImpl 仅使用数据库检查用户,如果未找到用户,则抛出 UsernameNotFoundException。也许这里有问题? 敬请指教。

提前致谢, 亚历克斯

最佳答案

此行为是由于 ExceptionTranslationFilter 将最终异常转换为:

Access is denied (user is anonymous); redirecting to authentication entry point

用户是匿名的,因为您的 UserDetailsS​​ervice 引发了异常。您收到 401 响应,因为它已在 BasicAuthenticationEntryPoint 中以这种方式实现在具有匿名用户主体的非 XMLHttpRequest(您的情况)的情况下,它充当身份验证入口点。

如果您希望显示拒绝访问页面(不给匿名用户进行身份验证的机会),则需要插入您自己的 AuthenticationEntryPoint使用http元素上的entry-point-ref属性(然后也可以让AccessDeniedHandler进入图片)。最终的实现看起来像这样:

import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;

public class CustomAuthEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException authException) throws IOException, ServletException {
        response.setStatus(SC_FORBIDDEN); /* You can also call an access denied handler here and let it handle some meaningful exception that you pass into the handle method. */
    }
}

PS:当然,在开始工作之前,您需要将新的身份验证入口点配置为 Spring bean。

关于java - PreAuthenticatedAuthenticationProvider UsernameNotFound 异常返回 401 而不是拒绝页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31402141/

相关文章:

java - Freemarker 配置的 Autowiring 失败

java - 配置 Swagger-UI 以获取 Spring 的 HttpSecurity Logout 端点

spring - java.lang.IllegalStateException : ApplicationEventMulticaster not initialized 错误

java - 可以在编译时操作 JVM 字节码吗?

在 android 中添加 google place API 时出现 java.lang.IllegalStateException

java - 上传图片到服务器

java - 即使使用@transactional注释后,如何在spring中解析 'No transaction is currently active'?

java - 如何将ThreadLocal从父线程复制到多个子线程?

java - 如何使用 Java 8 迭代 Map 以获得重复字符键的字符串

angularjs - Spring Security 实现最好没有 Spring Boot