Модуль Spring Boot Security выдает ошибку 403 при вызове с использованием axios из реакции, но отлично работает в почтальоне

У меня есть проект весенней загрузки, который использует весеннюю безопасность с токеном JWT. Это отлично работает в POSTMAN, но выдает ошибку 403 при использовании реагирующих аксиом. Ниже приведен код, используемый

SecurityConfig.java

    package com.cg.practice.EmployeeCRUD.config;
    
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.config.BeanIds;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.config.http.SessionCreationPolicy;
    import org.springframework.security.crypto.password.NoOpPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    import org.springframework.web.cors.CorsConfiguration;
    
    import com.cg.practice.EmployeeCRUD.Service.CustomUserService;
    import com.cg.practice.EmployeeCRUD.filter.EmployeeCRUDFilter;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        CustomUserService userService;
        
        @Autowired
        EmployeeCRUDFilter employeeCRUDFilter;
        
        /*
         * @Autowired CorsFilter corsFilter;
         */
    
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            // TODO Auto-generated method stub
            System.out.println("Hi1");
            auth.userDetailsService(userService);
        }
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return NoOpPasswordEncoder.getInstance();
        }
    
        @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
            @Override
        protected void configure(HttpSecurity http)  {
            // TODO Auto-generated method stub
            System.out.println("Hi2");
              try { 
                  CorsConfiguration corsConfiguration = new CorsConfiguration();
                    corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
                    corsConfiguration.setAllowedOrigins(List.of("http://localhost:3000"));
                    corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT","OPTIONS","PATCH", "DELETE"));
                    corsConfiguration.setAllowCredentials(true);
                    corsConfiguration.setExposedHeaders(List.of("Authorization"));
                  
                  http
                 // .addFilterBefore(corsFilter, SessionManagementFilter.class) 
                  .csrf().disable().authorizeRequests().antMatchers("/authenticate/")
                  .permitAll().anyRequest().authenticated()
                  .and().exceptionHandling().and().sessionManagement()
                  .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                  .and().cors().configurationSource(request -> corsConfiguration);
    ;
          http.addFilterBefore(employeeCRUDFilter, UsernamePasswordAuthenticationFilter.class);
                  } 
              catch (Exception e) 
              { 
                      // TODO: handle exception 
                      e.printStackTrace(); 
                      }
                  }
             
        }

СотрудникCRUDFilter.java

package com.cg.practice.EmployeeCRUD.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import com.cg.practice.EmployeeCRUD.Service.CustomUserService;
import com.cg.practice.EmployeeCRUD.util.JwtUtil;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;

@Component
public class EmployeeCRUDFilter extends OncePerRequestFilter {

    @Autowired
    JwtUtil jwtUtil;
    @Autowired
    CustomUserService userService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            {
        // TODO Auto-generated method stub
        String authorizationHeader = request.getHeader("Authorization");

        String token = null;
        String userName = null;
try
{
        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            token = authorizationHeader.substring(7);
            userName = jwtUtil.extractUsername(token);
        }

        if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = userService.loadUserByUsername(userName);

            if (jwtUtil.validateToken(token, userDetails)) {

                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        filterChain.doFilter(request, response);
    }   
catch (Exception e) {
    // TODO: handle exception
    e.printStackTrace();
}
            }
    }

Метод CRUDController

@PostMapping("/authenticate")
    
    public String generateToken(@RequestBody AuthRequest authRequest) throws Exception
    {

        try {
        authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                authRequest.getUserName(),authRequest.getPassword())        
                        );
        }
        catch (Exception e) {
            return "Invalid User/Password";
        }
        return jwtUtil.generateToken(authRequest.getUserName());
    }

Реагировать Authservice.js

import http from '../Mycomponent/http-common';

class AuthService{

    authenticate(){
        return http.post("/authenticate", {"userName":"Dip","password":"password@123"}
        )
        .then(response => {
            console.info(response.data)
            if (response.data.accessToken) {
              localStorage.setItem("user", JSON.stringify(response.data));
            }
            return response.data;
          })
          .catch(error =>{
            console.info("Error :"+error);
          });
    }
}
export default new AuthService();

http-common.js

import axios from 'axios';

export default axios.create({
  baseURL: "http://localhost:8080/CRUD",
  headers: {
    "Content-type": "application/json"
      }
});

Это дает ошибку 403 в браузере

Failed to load resource: the server responded with a status of 403 ()
AuthService.js:16 Error :Error: Request failed with status code 403
:8080/CRUD/getAll:1          Failed to load resource: the server responded with a status of 403 ()
createError.js:16 Uncaught (in promise) Error: Request failed with status code 403
    at createError (createError.js:16:1)
    at settle (settle.js:17:1)
    at XMLHttpRequest.onloadend (xhr.js:66:1)

Кто-нибудь может помочь. Я застрял на нем в течение длительного времени. Я что-то упускаю? Я новичок в реакции.

Отлично работает в PostMAN

Похоже, вы не отправляете какие-либо учетные данные с запросом axios. Разве вы не должны устанавливать заголовок авторизации? Или вы используете какое-то промежуточное ПО, которое должно это делать?

Michal Trojanowski 21.03.2022 09:28

authentication(){ return http.post("/authenticate", {"userName":"Dip","password":"password@123"}) Я делаю это для нее. Это какая-то ошибка, которую я делаю?

Dipanjan Bhattacharya 21.03.2022 10:41

Запрос к /authenticate возвращает 403 или запрос к /CRUD?

Michal Trojanowski 21.03.2022 13:30
локальный хост: 8080/CRUD/аутентификация возвращает 403. Он не затрагивает серверную часть.
Dipanjan Bhattacharya 21.03.2022 14:18

В настройках безопасности вы определяете /authenticate как единственный маршрут с анонимным доступом. Я думаю, что это должно быть /CRUD/authenticate, если это то, что вы звоните, чтобы войти.

Michal Trojanowski 23.03.2022 10:17

См. базовый URL-адрес, в который включен CRUD. Любая проблема, которую вы видите в CORS на стороне сервера?

Dipanjan Bhattacharya 23.03.2022 12:45

Обратите внимание, что Spring Security имеет встроенную поддержку аутентификации JWT, поэтому нет необходимости создавать свою собственную. Вы можете проверить образец здесь.

Eleftheria Stein-Kousathana 24.03.2022 14:01

при использовании почтальона я могу подключиться и получить этот токен jwt, но от реакции я получаю эту ошибку cors

Dipanjan Bhattacharya 24.03.2022 14:11
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
8
103
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Похоже, вы пропустили Authorization в заголовке при настройке экземпляра axios.

authentication(){ return http.post("/authenticate", {"userName":"Dip","password":"password@123"}) Я делаю это с ней. Это какая-то ошибка, которую я делаю? - Не могли бы вы показать пример, что вы имеете в виду

Dipanjan Bhattacharya 21.03.2022 10:42

для аутентификации первого запроса я генерирую токен jwt, поэтому требуется ли авторизация?

Dipanjan Bhattacharya 21.03.2022 11:24
Ответ принят как подходящий

Я думаю здесь кроется проблема:

http
    .csrf().disable().authorizeRequests().antMatchers("/authenticate/")
    .permitAll().anyRequest().authenticated()
    .and().exceptionHandling().and().sessionManagement()
    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and().cors().configurationSource(request -> corsConfiguration);

Вы сообщаете spring о запросах permitAll к конечной точке /authenticate/ и требуете аутентификации для всех остальных запросов. Но из внешнего интерфейса вы делаете запрос к /CRUD/authenticate/. Вот почему вы получаете 403, потому что этот путь должен быть аутентифицирован — это означает, что запрос уже должен иметь заголовок Authorization. Я думаю, что это должно работать, если вы измените первую строку на это:

.csrf().disable().authorizeRequests().antMatchers("/CRUD/authenticate/")

В бэкэнде Spring Boot он формирует URL-адрес, как в файле application.properties. У меня есть server.servlet.contextPath=/CRUD, который формирует URL-адрес как localhost:8080/CRUD/authenticate.

Dipanjan Bhattacharya 24.03.2022 08:20

Я понимаю. Как насчет завершающей косой черты в antMatcher. Это должно быть там?

Michal Trojanowski 24.03.2022 16:16

Да, я пропустил косую черту в ответе. Он должен быть в антматчере.

Dipanjan Bhattacharya 25.03.2022 09:27

Другие вопросы по теме