Spring Security 6,Angular 13 CORS问题OPTIONS请求

ohtdti5x  于 2023-10-20  发布在  Spring
关注(0)|答案(1)|浏览(142)

我在Springboot中有这个应用程序作为后端,而angular应用程序作为前端,我的问题是,当我从angular向后端执行http get调用时,它会用
'从源' http://localhost:4200 '访问位于' http://localhost:8080/operator/getall '的XMLHttpRequest已被CORS策略阻止:对印前检查请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。
为了更好地理解,这里有一些拦截器的后端和前端项目的图片以及所有安全配置的东西。

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {

    private final JwtAuthenticationFilter jwtAuthenticationFilter;
    private final UserService userService;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http.csrf(AbstractHttpConfigurer::disable)
                .cors(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(request -> request.requestMatchers("/auth/**")
                        .permitAll().requestMatchers("/operator/**").hasAnyRole("ADMIN").anyRequest().authenticated())
                .sessionManagement(manager -> manager.sessionCreationPolicy(STATELESS))
                .authenticationProvider(authenticationProvider()).addFilterBefore(
                        jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userService.userDetailService());
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config)
            throws Exception {
        return config.getAuthenticationManager();
    }
}
@RestController
@RequestMapping(path = "/operator")
@CrossOrigin(origins = "http://localhost:4200/", maxAge = 3600)
@RequiredArgsConstructor
@PreAuthorize("hasRole('ADMIN')")
public class OperatoreController {

    @Autowired
    private OperatoreService operatoreService;

    @GetMapping(path = "/getall")
    public ResponseEntity<List<Operatore>> getAllOperatore(){
        return ResponseEntity.ok(operatoreService.getAll());
    }

}
@RestController
@RequestMapping(path = "/auth")
@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
@RequiredArgsConstructor
public class AuthenticationController {

    @Autowired
    private OperatoreService operatoreService;

    @Autowired
    private final AuthenticationServiceImpl authenticationService;

    @PostMapping("/login")
    public ResponseEntity<JwtAuthenticationResponse> Login(@RequestBody LoginRequest request) {
        return ResponseEntity.ok(authenticationService.signin(request));
    }
}

执行调用的前端服务

@Injectable({
  providedIn: 'root'
})
export class HomeService {

  constructor(private http: HttpClient) { }

  getAll() {
    console.log(`${environment.apiUrl}/${environment.servizi.api.getAll}`)
    return this.http.get(`${environment.apiUrl}/${environment.servizi.api.getAll}`)
  }

}

拦截器

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
  constructor(private authenticationService: AuthService) {}

  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    // add authorization header with jwt token if available
    const currentUser = this.authenticationService.currentUserValue;
    if (currentUser && currentUser.token) {

      console.log("SEEET token "+ currentUser.token)
      /**request = request.clone({
       headers: request.headers.append("Authorization",`Bearer ${currentUser.token}`)
       });**/
      request = request.clone({
        setHeaders: {
          Authorization: `Bearer ${currentUser.token}`
        },
      });
    }

    return next.handle(request);
  }
}

更奇怪的是,只有在OperatoreController getall中的那个方法上返回这个错误,身份验证工作,它按预期返回jwt
!(https://i.stack.imgur.com/wzBXk.png)
还试穿了 Postman 的衣服
!(https://i.stack.imgur.com/xsM7B.png)

JwtAuthentication Filter

@Component

@AllArgsConstructor public class JwtAuthenticationFilter extends OncePerRequestFilter {

private final JwtServiceImpl jwtService;
private final TokenRepository tokenRepository;
private final UserDetail userService;
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request,
                                @NonNull HttpServletResponse response, @NonNull FilterChain filterChain)
        throws ServletException, IOException {
    final String authHeader = request.getHeader("Authorization");
    final String jwt;
    final String userEmail;
    if (StringUtils.isEmpty(authHeader) || !StringUtils.startsWith(authHeader, "Bearer ")) {
        filterChain.doFilter(request, response);
        return;
    }
    jwt = authHeader.substring(7);
    userEmail = jwtService.extractUserName(jwt);
    if (StringUtils.isNotEmpty(userEmail)
            && SecurityContextHolder.getContext().getAuthentication() == null) {
        UserDetails userDetails = userService.userDetailService()
                .loadUserByUsername(userEmail);
        var isTokenValid = tokenRepository.findByToken(jwt)
                .map(t -> !t.isExpired() && !t.isRevoked())
                .orElse(false);
        if (jwtService.isTokenValid(jwt, userDetails) && isTokenValid && userDetails.isEnabled()) {
            SecurityContext context = SecurityContextHolder.createEmptyContext();
            UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                    userDetails, null, userDetails.getAuthorities());
            authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            context.setAuthentication(authToken);
            SecurityContextHolder.setContext(context);
        }
    }
    filterChain.doFilter(request, response);
}

}

编辑1

经过一些修改,我做了我的代码,我发现Angular提出了一个OPTIONS请求,但要访问/operator/getAll中的请求方法,它必须经过身份验证,所以我的JwtAuthenticationFilter丢弃了它,然后CorsError appers,事实上,如果我们试图将方法移动到不需要JWT接受请求的AuthenticationController中,

但是我不能添加jwt到CORS策略的OPTIONS请求,我希望访问OperatorController请求必须经过身份验证,所以我不知道如何解决这个问题,有人能帮助我吗

deikduxw

deikduxw1#

您需要设置代理配置才能使其工作。我怀疑你尝试的是不正确的,也许?
对于生产,你需要配置你的服务器从相同的URL服务的应用程序,或编排你的应用程序与反向代理等。
为了让开发服务器工作,你可以使用Angular CLI的内置代理。
https://angular.io/guide/build#proxying-to-a-backend-server
1.创建proxy.conf.json

{
  "/api": {
    "target": "http://localhost:8080",
    "secure": false,
    "changeOrigin": true,
    "pathRewrite": {
      "^/api": ""
    }
  }
}

(the pathRewrite由你决定,我相信你现在不需要,但明智的做法是为后端调用提供一个url段)
1.在projects/<your projectname>/architect/serve下将此添加到angular.json

"options": {
  "proxyConfig": "proxy.conf.json"
}

现在ng serve应该可以工作了。

相关问题