Spring Security:从上下文外的Angular访问后端URL问题求助
嘿,我来帮你搞定Angular前端跨域访问JHipster 4.13.1后端的问题!结合你贴出的Spring Security配置,咱们一步步调整,解决这个问题:
你已经在Security配置里加了corsFilter,但得确保这个过滤器的规则允许你的前端域名访问。JHipster自带了CORS配置的支持,直接在application.yml里配置就行:
jhipster: cors: allowed-origins: "http://localhost:4200" # 替换成你的Angular前端实际地址(带端口) allowed-methods: "*" allowed-headers: "*" exposed-headers: "Authorization,Link,X-Total-Count" allow-credentials: true max-age: 1800
这里allow-credentials: true非常重要,因为你用到了rememberMe和CSRF,需要浏览器携带cookie到后端。另外,你在Security里的addFilterBefore(corsFilter, CsrfFilter.class)这行代码是对的,确保CORS过滤在CSRF之前执行。
你的配置里用了CookieCsrfTokenRepository.withHttpOnlyFalse(),这步做对了!因为Angular需要从cookie里读取CSRF token,而HttpOnly设为false才能让前端JS访问到这个cookie。记得把rememberMe的配置补全,确保rememberMeServices正确注入:
@Override protected void configure(HttpSecurity http) throws Exception { http .csrf() .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .and() .addFilterBefore(corsFilter, CsrfFilter.class) .exceptionHandling() .authenticationEntryPoint(problemSupport) .accessDeniedHandler(problemSupport) .and() .rememberMe() .rememberMeServices(rememberMeServices) // 这里要确保已经正确注入对应的bean // 别忘了加上授权规则,比如放开登录、注册等无需认证的接口 .and() .authorizeRequests() .antMatchers("/api/auth/**", "/api/register").permitAll() .anyRequest().authenticated(); }
Angular这边要配合后端的CSRF和CORS设置,主要做两件事:
- 让HttpClient自动处理CSRF token
- 确保请求携带cookie(withCredentials)
首先,在app.module.ts里配置CSRF的cookie和请求头名称(和后端对应):
import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http'; @NgModule({ imports: [ HttpClientModule, HttpClientXsrfModule.withOptions({ cookieName: 'XSRF-TOKEN', // 和后端CSRF配置的cookie名一致 headerName: 'X-XSRF-TOKEN' // 后端期望的CSRF请求头名 }) ] }) export class AppModule { }
然后,为了所有请求都自动携带cookie,最好写一个全局HTTP拦截器:
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http'; @Injectable() export class CredentialsInterceptor implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler) { // 克隆请求,添加withCredentials属性 const clonedRequest = req.clone({ withCredentials: true }); return next.handle(clonedRequest); } }
接着在app.module.ts里注册这个拦截器:
import { HTTP_INTERCEPTORS } from '@angular/common/http'; @NgModule({ providers: [ { provide: HTTP_INTERCEPTORS, useClass: CredentialsInterceptor, multi: true } ] }) export class AppModule { }
如果还是遇到问题,可以按以下步骤排查:
- CORS错误:检查后端
allowed-origins是否包含前端的完整地址(包括http/https和端口),比如前端是http://localhost:4200,就不能只写localhost。 - 403 Forbidden:打开浏览器开发者工具的Network面板,查看请求头是否有
X-XSRF-TOKEN,cookie里是否有XSRF-TOKEN;同时检查后端的授权规则,确保你访问的URL是允许的。 - RememberMe不生效:检查rememberMe的cookie域名是否设置正确,如果前后端域名不同,需要把cookie的domain设为两者的父域名,或者确保cookie的domain兼容。
内容的提问来源于stack exchange,提问作者skin27

