복붙노트

[SPRING] 403 대신 봄 보안 익명 401

SPRING

403 대신 봄 보안 익명 401

Java Config에서 제공하는 권한 부여 요청으로 봄 보안의 기본 동작에 문제가 있습니다.

http
       ....
       .authorizeRequests()
          .antMatchers("/api/test/secured/*").authenticated()

예를 들어 / api / test / secured / user를 로그인하지 않고 (익명 사용자와 함께) 호출하면 403 Forbidden이 반환됩니다. 익명 사용자가 authenticated () 또는 @PreAuthorize 리소스로 보안을 설정하려는 경우 상태를 Unauthorized로 변경하는 쉬운 방법이 있습니까?

해결법

  1. ==============================

    1.나는 여기에 해결책을 가지고있다.

    나는 여기에 해결책을 가지고있다.

    http
       .authenticationEntryPoint(authenticationEntryPoint)
    

    AuthenticationEntryPoint 소스 코드 :

    @Component
    public class Http401UnauthorizedEntryPoint implements AuthenticationEntryPoint {
    
        private final Logger log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint.class);
    
        /**
         * Always returns a 401 error code to the client.
         */
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2) throws IOException,
                ServletException {
    
            log.debug("Pre-authenticated entry point called. Rejecting access");
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied");
        }
    }
    
  2. ==============================

    2.스프링 보안 4.x에는 이미 클래스가 있습니다.

    스프링 보안 4.x에는 이미 클래스가 있습니다.

    org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint 
    

    봄 부츠도 하나 포함

    org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint
    

    개발자가 401 응답으로 규격을 준수하도록 요구하는 두 가지 이점은 헤더 WWW-Authenticate가 설정되어야한다는 것을 요구합니다. 예를 들어 401 응답은 다음과 같습니다.

    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: Bearer realm="example",
                       error="invalid_token",
                       error_description="The access token expired"
    

    그래서 보안 설정에서 클래스의 bean을 정의하고 autowire한다.

    예를 들어 봄 부팅 응용 프로그램과 함께 :

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled=true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
    
        @Bean
        public Http401AuthenticationEntryPoint securityException401EntryPoint(){
    
            return new Http401AuthenticationEntryPoint("Bearer realm=\"webrealm\"");
        }
    
        @Autowired
        private Http401AuthenticationEntryPoint authEntrypoint;
    ...
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .antMatchers("/login").anonymous()
                    .antMatchers("/").anonymous()
                    .antMatchers("/api/**").authenticated()
                .and()
                .csrf()
                    .disable()
                    .headers()
                    .frameOptions().disable()
                .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .logout()
                    .permitAll()
             .exceptionHandling().authenticationEntryPoint(authEntrypoint);
    }
    

    관련 회선은 다음과 같습니다.

     .exceptionHandling().authenticationEntryPoint(authEntrypoint);
    
  3. ==============================

    3.Spring 부트 2 클래스 Http401AuthenticationEntryPoint가 제거되었습니다 (스프링 부트 이슈 10725 참조).

    Spring 부트 2 클래스 Http401AuthenticationEntryPoint가 제거되었습니다 (스프링 부트 이슈 10725 참조).

    Http401AuthenticationEntryPoint 대신 HttpStatus.UNAUTHORIZED와 함께 HttpStatusEntryPoint를 사용하십시오.

    http.exceptionHandling()
        .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
    
  4. ==============================

    4.예외를 기반으로 사용자 정의를 수행하려면 AuthenticationEntryPoint를 확장해야합니다.

    예외를 기반으로 사용자 정의를 수행하려면 AuthenticationEntryPoint를 확장해야합니다.

    @ControllerAdvice
    public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
      @Override
      public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
          throws IOException, ServletException {
        // 401
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed");
      }
    
      @ExceptionHandler (value = {AccessDeniedException.class})
      public void commence(HttpServletRequest request, HttpServletResponse response,
          AccessDeniedException accessDeniedException) throws IOException {
        // 401
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization Failed : " + accessDeniedException.getMessage());
      }
    }
    

    위의 사용자 지정 AuthenticationEntryPoint를 아래와 같이 SecurityConfig에 지정하십시오.

    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity (prePostEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
      @Override
      protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
            .authenticationEntryPoint(new MyAuthenticationEntryPoint());
      }
    }
    
  5. from https://stackoverflow.com/questions/30643029/spring-security-anonymous-401-instead-of-403 by cc-by-sa and MIT license