Почему Spring Boot WebSocket всегда возвращает код 403 при использовании Postman?

Как настроить конфигурацию чата на веб-сокетах таким образом, чтобы запросы через Postman не возвращали ошибку 403?
  • 11 октября 2023 г. 8:44
Ответы на вопрос 2
Spring Boot WebSocket возвращает ошибку 403, когда запросы через Postman не аутентифицированы или не имеют необходимых разрешений для доступа к веб-сокетам. Это может быть вызвано отсутствием токена аутентификации или настройками безопасности.

Чтобы настроить конфигурацию чата на веб-сокетах таким образом, чтобы запросы через Postman не возвращали ошибку 403, вы можете выполнить следующие шаги:

1. Убедитесь, что у вас есть механизм аутентификации, который генерирует токены аутентификации для веб-сокетов. Например, вы можете использовать JSON Web Tokens (JWT).

2. Создайте фильтр аутентификации, который будет проверять наличие и правильность токена аутентификации в запросе. Если токен валиден, вы можете разрешить доступ к веб-сокетам, иначе возвращайте ошибку 403.

Пример фильтра аутентификации с использованием JWT:

```java
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final TokenProvider tokenProvider;
    private final CustomUserDetailsService customUserDetailsService;

    public JwtAuthenticationFilter(TokenProvider tokenProvider, CustomUserDetailsService customUserDetailsService) {
        this.tokenProvider = tokenProvider;
        this.customUserDetailsService = customUserDetailsService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            String jwt = extractJwtFromRequest(request); // извлекаем токен из запроса

            if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
                Long userId = tokenProvider.getUserIdFromToken(jwt);
                UserDetails userDetails = customUserDetailsService.loadUserById(userId);

                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (Exception ex) {
            logger.error("Failed to authenticate JWT", ex);
            response.setStatus(HttpServletResponse.SC_FORBIDDEN); // возвращаем ошибку 403, если аутентификация не удалась
            return;
        }

        filterChain.doFilter(request, response);
    }

    private String extractJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}
```

3. Добавьте фильтр аутентификации в конфигурацию Spring Security:

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private TokenProvider tokenProvider;
    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter(){
        return new JwtAuthenticationFilter(tokenProvider, customUserDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http 
            .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("/api/auth/**")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and()
            ...
    }
}
```

В данном примере фильтр аутентификации добавляется перед стандартным фильтром аутентификации Spring Security и проверяет наличие и правильность токена в заголовке "Authorization". Если токен валиден, аутентификация успешна и доступ разрешен.

После настройки конфигурации чата на веб-сокетах таким образом, запросы через Postman не должны возвращать ошибку 403.
Попробуйте использовать бин `WebSocketSecurityConfig` с аннотациями `@Configuration` и `@EnableWebSocketSecurity`. Этот бин содержит метод `messageAuthorizationManager()`, который возвращает менеджер авторизации для сообщений. Убедитесь, что возвращаемый менеджер авторизации требует наличия роли "USER". Возможно, ваши запросы отправляются без авторизации, поэтому проверьте этот момент.
Похожие вопросы