Grails Spring安全插件应该以401而不是403响应

Grails Spring安全插件应该以401而不是403响应,grails,spring-security,Grails,Spring Security,当web会话过期时,Spring Security将以403 HTTP状态响应。理想情况下,它会以401作为回应。未经授权和禁止是不同的。如果存在有效会话,则对安全资源的请求只应返回403,但用户只是没有对所述资源的权限。如果资源是安全的,并且没有经过身份验证的会话,那么Spring Security应该返回401 我的应用程序需要非常具体地区分这两个错误代码 我的问题是,如何定制这种行为?参考我关于401和403之间差异的论点,.以下是我的解决方案: @Configuration public

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

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


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

以下是我的解决方案:

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

以下是我的解决方案:

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

在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)


在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)



从源代码看,它似乎不是可定制的:嗯,这令人失望。没有什么能阻止您用自己的实现此功能的实现替换默认实现。也可能是一个好的拉取请求(:查看源代码,它似乎不可自定义:嗯,这很令人失望。没有任何东西阻止您用自己的实现此功能的实现替换默认实现。也可能是一个好的拉取请求(:从源代码看,它似乎不可自定义:嗯,这很令人失望。没有什么能阻止您用自己的实现此功能的实现替换默认实现。这可能也是一个很好的拉取请求(:有趣。感谢您的回复。我需要在resources.groovy中做些什么才能让它工作,还是
@Configuration
BeanPostProcessor
子类为我做些什么?这不起作用。Spring安全性仍然返回403。您确定配置类包含在您的上下文中吗配置?顺便说一句,我正在使用Java,所以我不知道Groovy配置。在Java中,您只需要将它包括在您的上下文配置中。很有趣。感谢您的响应。在参考资料中有什么我需要做的吗。Groovy要使此工作正常,还是执行
@configuration
BeanPostProcessor
子类让我们为我做吧?这不起作用。Spring Security仍然返回403。您确定配置类包含在您的上下文配置中吗?顺便说一句,我正在使用Java,所以我不知道Groovy配置。在Java中,您只需要将其包含在您的上下文配置中。很有趣。感谢您的响应。是否有我需要在resources.groovy中执行的所有操作,或者
@Configuration
BeanPostProcessor
子类是否为我执行这些操作?这不起作用。Spring安全性仍然返回403。您确定配置类包含在您的上下文配置中吗?顺便说一句,我正在使用Java,所以我没有了解Groovy配置。在Java中,您只需在上下文配置中包含它。