Как настроить страницу 403 Запрещено / Доступ запрещен с помощью Spring Security - PullRequest
1 голос
/ 14 апреля 2020

Я младший веб-разработчик, и мне нужно настроить страницу ошибки 403 с помощью реакции js, я нашел другие проекты, реализующие интерфейс AccessDeniedHandler, но я не знаю, как использовать его в своем классе конфигурации безопасности .

Это мой класс CustomAccessDeniedHandler:

@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
    private static Logger logger = LoggerFactory.getLogger(CustomAccessDeniedHandler.class);

    @Override
    public void handle(HttpServletRequest httpServletRequest,
                       HttpServletResponse httpServletResponse,
                       AccessDeniedException e) throws IOException, ServletException {
        System.out.println("accessDenied");
        Authentication auth
                = SecurityContextHolder.getContext().getAuthentication();

        if (auth != null) {
            logger.info("User '" + auth.getName()
                    + "' attempted to access the protected URL: "
                    + httpServletRequest.getRequestURI());
        }

        httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/accessDenied");
    }
}

Это класс конфигурации безопасности:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    AppUserService userDetailsService;
    @Autowired
    private AccessDeniedHandler accessDeniedHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf()
                .disable()
                .exceptionHandling()
                .authenticationEntryPoint(new Http403ForbiddenEntryPoint() {})
                .and()
                .authenticationProvider(getProvider())
                .formLogin()
                .loginPage("/login")
                .successHandler(new AuthentificationLoginSuccessHandler())
                .failureHandler(new SimpleUrlAuthenticationFailureHandler())
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(new AuthentificationLogoutSuccessHandler())
                .invalidateHttpSession(true)
                .and()
                .authorizeRequests()
                .antMatchers("/login").permitAll()
                .antMatchers("/logout").permitAll()
                .antMatchers("/api/categories").hasAuthority("USER")
                .antMatchers("/api/createCategory").hasAuthority("ADMIN")
                .anyRequest().permitAll();
    }

    private class AuthentificationLoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
                throws IOException, ServletException {
            response.setStatus(HttpServletResponse.SC_OK);
        }
    }

    private class AuthentificationLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
        @Override
        public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
                                    Authentication authentication) throws IOException, ServletException {
            response.setStatus(HttpServletResponse.SC_OK);
        }
    }

    @Bean
    public AuthenticationProvider getProvider() {
        AppAuthProvider provider = new AppAuthProvider();
        provider.setUserDetailsService(userDetailsService);
        return provider;
    }

    @Bean
    public AccessDeniedHandler accessDeniedHandler(){
        return new CustomAccessDeniedHandler();
    }
}

1 Ответ

1 голос
/ 15 апреля 2020

Что вам нужно сделать, это создать @Bean

@Bean
public AccessDeniedHandler accessDeniedHandler(){
    return new CustomAccessDeniedHandler();
}

, который у вас уже есть, и затем добавить этот обработчик в объект безопасности http, например так:

http.csrf()
            .disable()
            .exceptionHandling()
            .authenticationEntryPoint(new Http403ForbiddenEntryPoint() {}) //remove this line or use Http401UnauthorizedEntryPoint instead
            .and()
            .authenticationProvider(getProvider())
            .formLogin()
            .loginPage("/login")
            .successHandler(new AuthentificationLoginSuccessHandler())
            .failureHandler(new SimpleUrlAuthenticationFailureHandler())
            .and()
            .logout()
            .logoutUrl("/logout")
            .logoutSuccessHandler(new AuthentificationLogoutSuccessHandler())
            .invalidateHttpSession(true)
            .and()
            .authorizeRequests()
            .antMatchers("/login").permitAll()
            .antMatchers("/logout").permitAll()
            .antMatchers("/api/categories").hasAuthority("USER")
            .antMatchers("/api/createCategory").hasAuthority("ADMIN")
            .anyRequest().permitAll()
            .and()
            .exceptionHandling().accessDeniedHandler(accessDeniedHandler());

Как вы может видеть, что вы пропали:

.and().exceptionHandling().accessDeniedHandler(accessDeniedHandler());

Дополнительно, удалите

@Autowired
private AccessDeniedHandler accessDeniedHandler;

, поскольку вы не должны автоматически связывать компонент, вы должны создать его с пользовательской реализацией.

РЕДАКТИРОВАТЬ : Если у вас есть @RestControllerAdvice или @ControllerAdvice в качестве глобального обработчика исключений, вы должны сделать следующее:

@ExceptionHandler(Exception.class)
public ResponseEntity<?> exception(Exception exception) throws Exception {
        if (exception instanceof AccessDeniedException) {
            throw exception;
        } 
...

, тогда это должно сработать, потому что, когда вы бросаете исключение, оно будет go для пользовательского обработчика, который мы делаем, что вы написали. Также вы можете отладить ExceptionTranslationFilter метод handleSpringSecurityException

код из ExceptionTranslationFilter

private void handleSpringSecurityException(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain, RuntimeException exception)
            throws IOException, ServletException {
        if (exception instanceof AuthenticationException) {
            logger.debug(
                    "Authentication exception occurred; redirecting to authentication entry point",
                    exception);

            sendStartAuthentication(request, response, chain,
                    (AuthenticationException) exception);
        }
        else if (exception instanceof AccessDeniedException) {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authenticationTrustResolver.isAnonymous(authentication) || authenticationTrustResolver.isRememberMe(authentication)) {
                logger.debug(
                        "Access is denied (user is " + (authenticationTrustResolver.isAnonymous(authentication) ? "anonymous" : "not fully authenticated") + "); redirecting to authentication entry point",
                        exception);

                sendStartAuthentication(
                        request,
                        response,
                        chain,
                        new InsufficientAuthenticationException(
                            messages.getMessage(
                                "ExceptionTranslationFilter.insufficientAuthentication",
                                "Full authentication is required to access this resource")));
            }
            else {
                logger.debug(
                        "Access is denied (user is not anonymous); delegating to AccessDeniedHandler",
                        exception);

                accessDeniedHandler.handle(request, response,
                        (AccessDeniedException) exception);
            }
        }
    }

, где вы можете увидеть, что accessDeniedHandler.handle(request, response,(AccessDeniedException) exception);, в вашем случае CustomAccessDeniedHandler, позвоните.

Я только что попробовал, и он работает нормально (у меня @ControllerAdvice в качестве глобального обработчика исключений)

EDIT2: Вы должны удалить это line

.authenticationEntryPoint(new Http403ForbiddenEntryPoint() {})

from SecurityConfig или измените его на Http401UnauthorizedEntryPoint. Это проблема в вашем случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...