如何解决发送创建新用户的 POST 请求时出现 403 禁止的问题

问题描述 投票:0回答:1

尽管我在配置类中允许了该路径,但当我通过 Postman 发送 POST 请求时,仍然收到 403 禁止。如果我禁用 Spring Security(允许所有请求),该请求会起作用。

我在终端上收到此消息:

2024-12-19T00:21:09.253+01:00 DEBUG 15372 --- [backend-2in1-project] [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : Securing POST /api/v1/auth/register
2024-12-19T00:21:09.253+01:00 DEBUG 15372 --- [backend-2in1-project] [nio-8080-exec-3] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to anonymous SecurityContext
2024-12-19T00:21:09.253+01:00 DEBUG 15372 --- [backend-2in1-project] [nio-8080-exec-3] o.s.s.w.a.Http403ForbiddenEntryPoint     : Pre-authenticated entry point called. Rejecting access

配置类

package com.momentstock.backend._in1.project.security;
import lombok.RequiredArgsConstructor;
import org.apache.catalina.filters.CorsFilter;
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.servlet.config.annotation.CorsRegistry;

import java.util.List;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
//@EnableGlobalMethodSecurity(prePostEnabled = true) // to enable @preAuthorize
public class SecurityConfig {
    private final UserDetailsService userDetailsService;
    private final JwtAuthFilter jwtAuthFilter;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf(AbstractHttpConfigurer::disable)
                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                .authorizeHttpRequests(con -> con
                                .requestMatchers("/auth/**").permitAll()
                                .requestMatchers("/users/**").hasRole("USER")
                                .requestMatchers("/admin/**").hasRole("ADMIN")
                                .requestMatchers("/api/v1/orders/payment/callback").permitAll()
                                .requestMatchers("/welcome/**").permitAll()
//              .requestMatchers("/testKey").permitAll()
                                .requestMatchers(HttpMethod.DELETE, "/users/user/me/delete-account").authenticated()
                                .anyRequest().authenticated()
                )
//              .authorizeHttpRequests(auth -> auth .anyRequest().permitAll())

                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(List.of(
                "https://api.flutterwave.com",
                "https://api.paystack.co",
                "https://sandbox.interswitchng.com"
        ));
        configuration.addAllowedOrigin("*");
        configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
        configuration.setAllowedHeaders(List.of("*")); // Allow all headers
        configuration.setExposedHeaders(List.of("Authorization", "Content-Type")); // Optional, expose specific headers
        configuration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration); // Apply to all endpoints
        return source;
    }
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }
    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }
    @Bean
    public ModelMapper modelmapper(){
        return new ModelMapper();
    }

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }


}

控制器:

@RestController
@RequiredArgsConstructor
@RequestMapping("${api.prefix}/auth")
public class UserAuthController {
    private final IUserService userService;
    private final UserRepository userRepository;
    private final VerificationTokenRepository tokenRepository;
    private final JwtTokenProvider tokenProvider;

    @PostMapping("/register")
    public ResponseEntity<String> registerUser(@RequestBody CreateUserRequest request){
        userService.registerUser(request);
        return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully, check your email complete verification");
    }
    
    @PostMapping("/login")
    public ResponseEntity<ApiResponse> loginUser(@RequestBody LoginRequest request){
        try {
            LoginResponse loginResponse = userService.loginUser(request);
            return ResponseEntity.ok(new ApiResponse("Success", loginResponse));
        } catch (AuthenticationException e) {
            return ResponseEntity.status(BAD_REQUEST).body(new ApiResponse(e.getMessage(), null));
        }
    }

用户详细信息:

package com.momentstock.backend._in1.project.security;

import com.momentstock.backend._in1.project.enums.Role;
import com.momentstock.backend._in1.project.models.User;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Data
public class UserRegDetails implements UserDetails {

    private String userName;
    private String password;
    private boolean isEnabled;
    private Role role;

    public UserRegDetails(User user) {
        this.userName = user.getEmail();
        this.password = user.getPassword();
        this.isEnabled = user.isEnabled();
        this.role = Role.valueOf(user.getRole().name());
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return role != null
                ? List.of(new SimpleGrantedAuthority(role.name().toUpperCase()))
                : List.of();
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return userName;
    }

    @Override
    public boolean isAccountNonExpired() {
//      return UserDetails.super.isAccountNonExpired();
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
//      return UserDetails.super.isAccountNonLocked();
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
//      return UserDetails.super.isCredentialsNonExpired();
        return true;
    }

    @Override
    public boolean isEnabled() {
//      return UserDetails.super.isEnabled();
        return isEnabled;
    }
}

服务

@Service
@RequiredArgsConstructor
public class UserRegDetailsService implements UserDetailsService {
    private final UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        return userRepository.findByEmail(email).map(UserRegDetails::new).orElseThrow(() -> new UsernameNotFoundException("User not found"));
    }
}
java spring-boot spring-security http-status-code-403 restful-authentication
1个回答
0
投票

我有一个配置整个 CORS 主题的新类:

@Configuration
public class CorsConfig implements WebMvcConfigurer {

  protected static final String[] CORS_ORIGIN_DOMAIN_PROPERTY_KEYS = {
    "cors.allowed.origin",
    "cors.allowed.origin.public"
  };
  @Autowired
  private Environment env;

  /**
   * Configuration of cors.
   * @return WebMvcConfigurer
   */
  @Bean
  public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
      @Override
      public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
          .allowedOrigins(getAllAvailableOrigins())
          .allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS")
          .allowedHeaders("*")
          .allowCredentials(true);
      }
    };
  }

  private String[] getAllAvailableOrigins() {
    List < String > originList = new ArrayList < > ();
    for (String key: CORS_ORIGIN_DOMAIN_PROPERTY_KEYS) {
      String domain = env.getProperty(key);
      if (StringUtils.isNotEmpty(domain)) {
        String[] domainArray = domain.split(",");
        originList.addAll(Arrays.asList(domainArray));
      }
    }
    return originList.toArray(new String[] {});
  }

}

其中“cors.allowed.origin”和“cors.allowed.origin.public”是“application.properties”文件中配置的值。其中的值可以是:

cors.allowed.origin=http://localhost:4200,https://something.somethingElse.com

希望对您有帮助,

阿德里安

© www.soinside.com 2019 - 2024. All rights reserved.