我正在为我的 TFC 制作一个完整的堆栈应用程序,使用 Java 和 Spring Boot 作为后端,并使用 Angular 和前端。但是,当发出
GET
请求时,Spring Boot 安全性拒绝了我的请求。
这些是我得到的 Spring Boot 安全日志:
2024-12-23T12:42:44.562+01:00 INFO 14252 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-12-23T12:42:44.562+01:00 INFO 14252 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-12-23T12:42:44.565+01:00 INFO 14252 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 3 ms
2024-12-23T12:42:44.594+01:00 DEBUG 14252 --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy : Securing GET /park/emergencies
2024-12-23T12:42:44.594+01:00 DEBUG 14252 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : Securing GET /park/dinosaurs
2024-12-23T12:42:44.594+01:00 DEBUG 14252 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Securing GET /park/enclosures
2024-12-23T12:42:44.595+01:00 DEBUG 14252 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Securing GET /park/status
2024-12-23T12:42:44.790+01:00 DEBUG 14252 --- [nio-8080-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.790+01:00 DEBUG 14252 --- [nio-8080-exec-4] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.790+01:00 DEBUG 14252 --- [nio-8080-exec-1] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.790+01:00 DEBUG 14252 --- [nio-8080-exec-3] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Securing GET /error
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy : Securing GET /error
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Securing GET /error
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : Securing GET /error
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-1] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-4] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-3] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:45.892+01:00 DEBUG 14252 --- [nio-8080-exec-5] o.s.security.web.FilterChainProxy : Securing PUT /park/update
2024-12-23T12:42:45.897+01:00 DEBUG 14252 --- [nio-8080-exec-5] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:45.898+01:00 DEBUG 14252 --- [nio-8080-exec-5] o.s.security.web.FilterChainProxy : Securing PUT /error
2024-12-23T12:42:45.900+01:00 DEBUG 14252 --- [nio-8080-exec-5] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
我比较了前端和后端这两个令牌,它们是相同的,所以我不知道为什么他们拒绝我的请求。
这是我配置CORS的类:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final JwtFilter jwtFilter;
@Autowired
public SecurityConfig(JwtFilter jwtFilter){
this.jwtFilter=jwtFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.cors(Customizer.withDefaults())
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/register", "/auth/login").permitAll()
.anyRequest().authenticated()
)
.anonymous(AbstractHttpConfigurer::disable)
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("Authorization", "Content-Type", "Accept"));
configuration.setExposedHeaders(List.of("Authorization"));
configuration.setMaxAge(3600L);
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
这是
JwtFilter
:
@Component
public class JwtFilter implements Filter {
private final JwtUtil jwtUtil;
@Autowired
public JwtFilter(JwtUtil jwtUtil){
this.jwtUtil=jwtUtil;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String authHeader = httpRequest.getHeader("Authorization");
// System.out.println(authHeader+" solicitud desde el fornted");
String path = httpRequest.getRequestURI();
if ( path.startsWith("/auth")) {
chain.doFilter(request, response);
return;
}
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
try {
String userId=jwtUtil.validateToken(token);
httpRequest.setAttribute("userId",userId);
System.out.println("Token válido. UserId extraído: " + userId+" token "+authHeader);
} catch (Exception e) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
// System.out.println("Error al validar el token de jwt filter " + e.getMessage()+ " "+token);
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token inválido");
return;
}
}
chain.doFilter(request, response);
}
这是我用来生成令牌的类
@Component
public class JwtUtil {
@Value("${jwtKey}")
private String secretKey;
@Value("${jwtKeyExpiration}")
private long keyExpiration;
private Key key;
@PostConstruct
public void init() {
key = Keys.hmacShaKeyFor(secretKey.getBytes());
}
//genero un token con enlazado con el id del usuario mi key, que durara una 1 hora(despues el usuario
//Tendra que iniciar sesion de nuevo
public String generateToken(String userId) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.claims(claims)
.subject(userId)
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + keyExpiration))
.signWith(key, SignatureAlgorithm.HS256)
.compact();
}
public String validateToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey(key)
.build()
.parseSignedClaims(token)
.getPayload();
return claims.getSubject();
}
}
如何修复 403 CORS 错误?
首先我比较了令牌,后端在登录时是否正确地将它们发送到前端,以及是否相同。 我还查看了该网站上有关安全错误的其他帖子,但它对我不起作用。
我得到的 CORS 错误是:
Request URL:
http://localhost:8080/park/update
Request Method:
PUT
Status Code:
403 Forbidden
Remote Address:
[::1]:8080
Referrer Policy:
strict-origin-when-cross-origin
access-control-allow-credentials:
true
access-control-allow-origin:
http://localhost:4200
access-control-expose-headers:
Authorization
cache-control:
no-cache, no-store, max-age=0, must-revalidate
connection:
keep-alive
content-length:
0
date:
Mon, 23 Dec 2024 11:47:17 GMT
expires:
0
keep-alive:
timeout=60
pragma:
no-cache
vary:
Origin
vary:
Access-Control-Request-Method
vary:
Access-Control-Request-Headers
x-content-type-options:
nosniff
x-frame-options:
DENY
x-xss-protection:
0
accept:
application/json, text/plain, */*
accept-encoding:
gzip, deflate, br, zstd
accept-language:
es-ES,es;q=0.9
authorization:
Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzM0OTUzMTM0LCJleHAiOjE3MzQ5NTY3MzR9.x6VAuPFWyr2AaASPMO3Th7_6d7MDRyoEuwVdlxJf95U
connection:
keep-alive
content-length:
0
host:
localhost:8080
origin:
http://localhost:4200
referer:
http://localhost:4200/
sec-ch-ua:
"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"
sec-ch-ua-mobile:
?0
sec-ch-ua-platform:
"Windows"
sec-fetch-dest:
empty
sec-fetch-mode:
cors
sec-fetch-site:
same-site
user-agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
这是我在前端使用的拦截器:
export const authInterceptor: HttpInterceptorFn = (req: HttpRequest<any>, next: HttpHandlerFn): Observable<HttpEvent<any>> => {
const token = localStorage.getItem('token');
console.log("El token es del fronted "+token)
const clonedRequest = token
? req.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
},
withCredentials: true
})
: req.clone({ withCredentials: true });
return next(clonedRequest);
};
在设置允许的起点时尝试允许所有路径。
所以改变这个
configuration.setAllowedOrigins(List.of("http://localhost:4200"));
像这样:
configuration.setAllowedOrigins(List.of("http://localhost:4200/**"));