【问题标题】:Spring Security Plugin Should Respond with 401 instead of 403Spring Security 插件应该响应 401 而不是 403
【发布时间】:2015-08-16 20:10:44
【问题描述】:

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

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

我的问题是,如何自定义此行为?参考我关于 401 和 403 区别的论点,read this

【问题讨论】:

标签: grails spring-security


【解决方案1】:

这是我的解决方案:

@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;
        }
    }

【讨论】:

  • 有趣。感谢您的回复。我需要在 resources.groovy 中做些什么来完成这项工作,还是 @ConfigurationBeanPostProcessor 子类为我做这件事?
  • 这不起作用。 Spring Security 仍然返回 403。
  • 您确定配置类包含在您的上下文配置中吗?顺便说一句,我正在使用 Java,所以我不了解 Groovy 配置。在 Java 中,您只需将其包含在您的上下文配置中。
【解决方案2】:

在 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;
}

【讨论】:

    猜你喜欢
    • 2015-08-19
    • 2018-08-20
    • 2019-12-15
    • 2018-09-04
    • 2021-01-28
    • 2018-06-26
    • 2020-08-04
    • 2011-03-18
    相关资源
    最近更新 更多