当前位置: 首页 > 知识库问答 >
问题:

Spring Security插件应以401而不是403响应

越俊艾
2023-03-14

当web会话过期时,Spring Security将以403 HTTP状态进行响应。理想情况下,它会以401作为回应。未经授权和禁止是不同的。只有在存在有效会话的情况下,对安全资源的请求才应返回403,但用户只是没有对所述资源的权限。如果资源是安全的,并且没有经过身份验证的会话,那么Spring Security应该返回401。

我的应用程序需要非常具体地区分这两个错误代码。

我的问题是,我如何定制这种行为?参考我关于401和403之间差异的论点,请阅读本文。

共有2个答案

柴衡
2023-03-14

在Spring Boot 2.2.1中,我使用了从AuthenticationEntryPoint派生的类:

import java.io.IOException;
import javassist.NotFoundException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;


@ControllerAdvice
public class AppAuthenticationEntryPoint implements AuthenticationEntryPoint{

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException auth) throws IOException, ServletException {
        // 401
        setResponseError(response, HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed");
    }

    @ExceptionHandler (value = {AccessDeniedException.class})
    public void commence(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
        // 403
        setResponseError(response, HttpServletResponse.SC_FORBIDDEN, String.format("Access Denies: %s", accessDeniedException.getMessage()));
    }

    @ExceptionHandler (value = {NotFoundException.class})
    public void commence(HttpServletRequest request, HttpServletResponse response, NotFoundException notFoundException) throws IOException {
        // 404
        setResponseError(response, HttpServletResponse.SC_NOT_FOUND, String.format("Not found: %s", notFoundException.getMessage()));
    }

    @ExceptionHandler (value = {Exception.class})
    public void commence(HttpServletRequest request, HttpServletResponse response, Exception exception) throws IOException {
        // 500
        setResponseError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, String.format("Internal Server Error: %s", exception.getMessage()));
    }

    private void setResponseError(HttpServletResponse response, int errorCode, String errorMessage) throws IOException{
        response.setStatus(errorCode);
        response.getWriter().write(errorMessage);
        response.getWriter().flush();
        response.getWriter().close();
    }
}

在您的安全配置中(我有可通过OAuth2.0令牌访问的ResourceServer)

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {

        http.headers().frameOptions().sameOrigin();  // it is to fix issue with h2-console access

        http.csrf().disable()
            .authorizeRequests().antMatchers("/", "/callback", "/login**", "/webjars/**", "/error**").permitAll()
            .and()
            .authorizeRequests().antMatchers("/api/**").authenticated()
            .and()
            .authorizeRequests().antMatchers("/h2-console/**").permitAll()
            .and()
            .authorizeRequests().antMatchers("/swagger-ui.html").permitAll()
            .and()
            .authorizeRequests().antMatchers("/swagger-ui/**").permitAll()
            .and()
            .exceptionHandling().authenticationEntryPoint(new AppAuthenticationEntryPoint())
            .and()
            .logout().permitAll().logoutSuccessUrl("/");
    }

    @Bean
    public PrincipalExtractor getPrincipalExtractor(){
        return new KeyCloakUserInfoExtractorService();
    }

    @Autowired
    private ResourceServerTokenServices resourceServerTokenServices;
}
武博艺
2023-03-14

以下是我的解决方案:

@Configuration
public class WebCtxConfig  implements BeanPostProcessor {

        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof SessionManagementFilter) {
                SessionManagementFilter filter = (SessionManagementFilter) bean;
                filter.setInvalidSessionStrategy(new InvalidSessionStrategy() {

                    @Override
                    public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
                        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
                    }
                });
            }
            return bean;
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    }
 类似资料:
  • 我已经实现了JWT认证和授权。一切都很好,除了未经授权的场景 未经授权的情况:在不提供授权令牌的情况下对路由进行http调用。 结果:禁止403例,未批准403例 以下是我的完整课程: 备注: 我在UsernamePasswordAuthenticationFilter中遇到了同样的问题,我通过重写默认的AuthenticationFailureHandler解决了这个问题:

  • 问题内容: 随着spring引导 1.5.6.RELEASE我能够发送HTTP状态代码,而不是在描述如何让春天的安全响应未经授权(HTTP 401码)如果请求URI不进行认证,这样做: 使用课程。 我刚刚升级到Spring Boot 2.0.0.RELEASE,发现不再有此类(至少在该软件包中)。 问题: Spring Boot中是否存在此类()? 如果不是,那么在现有项目中保持相同行为,以便与依

  • 我在php中有两个oauth2客户端的例子,一个工作,另一个不工作,它返回一个错误: ([错误]= 我的问题是,oauth2服务器应该何时返回带有client_id的访问令牌响应,以及应该何时返回带有refresh_token的响应? 我的工作要求是: 我的不工作请求是: 既然它只是和变化,那么它什么时候应该来一个,什么时候应该来另一个?

  • 我正在使用Apache Camel CXF集成SOAP WebService。一切正常,但我注意到我的响应返回为HTTP 202而不是200。我有点担心,因为我知道很多人对之类的东西进行硬编码,这可能会破坏当前的服务。 我曾尝试使用不同的拦截器覆盖202到200的HTTP代码,但没有成功。此外,202表示已接受,这表示请求正在处理中但尚未完成。200表示正常,表示过程已完成。这是否意味着我在路上做

  • 使用Java进行一个简单的“delivery_quotes”调用进行测试,返回HTTP响应代码-403 我正在使用的客户ID和测试API密钥是正确的。任何帮助!

  • 我正在使用Spring Security和Spring Data Redis来跟踪具有自定义角色和权限的用户会话。当我尝试在浏览器中没有会话cookie的情况下访问预授权endpoint时,它应该返回401。相反,会创建一个新的(无效的)会话cookie,endpoint返回403。 这是我的安全配置: 我还使用MethodSecurityConfig和UserDetails的实现来解析用户身份验