Spring Security Plugin应该响应401而不是403

时间:2015-06-02 20:40:22

标签: grails spring-security

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

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

我的问题是,如何自定义此行为?关于我对401和403之间差异的论证,read this

2 个答案:

答案 0 :(得分:0)

以下是我的解决方案:

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

答案 1 :(得分:0)

在Spring Boot 2.2.1中,我已使用从AuthenticationEntryPoint派生的类来完成此操作:

'urlManager' => [
  'class' => 'yii\web\UrlManager',
  'showScriptName' => false,
  'enablePrettyUrl' => true,
  'rules' => [
    '/login' => 'site/login',
    '/logout' => 'site/logout',
    Yii::$app->language.'/'.'<controller:\w+>s'=>'<controller>/index',
    Yii::$app->language.'/'.'<controller:\w+>/<id:\d+>/<title:\w+>'=>'<controller>/view',
    Yii::$app->language.'/'.'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
    Yii::$app->language.'/'.'<controller:\w+>/<action:\w+>/<id:\d+>/*'=>'<controller>/<action>',
  ],
],

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

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();
    }
}