(서버에서 xsrf 또는 csrf를 허용한 경우)
Angular 6 이하에서는 http 전송 시 csrf 쿠키값을 헤더에 넣기 위해 HttpInterceptor를 사용하였는데, 여기에 csrf의 값이 담긴 쿠키값을 가져와 헤더를 생성하여야 하는 불편함이 있었습니다.
@Injectable({ providedIn: 'root' })
export class ApiInterceptor implements HttpInterceptor {
constructor(private cookieService: CookieService) { }
intercept(req: HttpRequest<any>, handler: HttpHandler): Observable<HttpEvent<any>> {
const headers = {
'My-Xsrf-Header': this.cookieService.get('My-Xsrf-Cookie'),
};
return handler.handle(
req.clone({ setHeaders: headers, withCredentials: true })
);
}
}
Angular 7 버전부터 HttpClientXsrfModule을 지원하여, 이를 보다 손쉽게 정리할 수 있습니다.
모듈에서 직접 설정할 수 있기 때문에 하드코딩이 상위로 올라와 관리 포인트를 줄일 수 있으며, 직관적인 확인이 가능합니다.
import { HttpClientModule, HttpClientXsrfModule } from '@angular/common/http';
imports: [
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'My-Xsrf-Cookie',
headerName: 'My-Xsrf-Header',
}),
],
이렇게 설정하였는데도 막상 실행해보면 에러가 발생한다면,
이는 인증을 이용한 요청방식을 위해 서버에서는 아래와 같이 Credentials 값을 true로 요구하고 있기 때문입니다.
response.setHeader("Access-Control-Allow-Credentials", "true")
Angular에서 http request 마다 또는 Interceptor에서 withCredential 값을 true로 설정해주어야 합니다.
@Injectable()
export class HttpConfigInterceptor implements HttpInterceptor {
constructor() {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
request = request.clone({
withCredentials: true
});
return next.handle(request);
}
}
Angular 17부터는 NgModule 없이 독립형 API를 사용하는 것이 기본입니다. 전역 HTTP 설정은 app.config.ts 파일에서 provideHttpClient라는 프로바이더 함수와 함께 제공되는 기능(feature)들을 통해 이루어집니다.
app.config.ts 파일에서 XSRF 설정과 인터셉터를 한 번에 구성합니다.
// src/app/app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
// 1. 필요한 함수들을 @angular/common/http에서 임포트
import { provideHttpClient, withXsrfConfiguration, withInterceptors, HttpInterceptorFn } from '@angular/common/http';
import { routes } from './app.routes';
// 2. 함수형 인터셉터 정의
const credentialsInterceptor: HttpInterceptorFn = (req, next) => {
const clonedReq = req.clone({
withCredentials: true,
});
return next(clonedReq);
};
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
// 3. HttpClient 관련 설정을 providers 배열에 추가
provideHttpClient(
// XSRF 설정
withXsrfConfiguration({
cookieName: 'My-Xsrf-Cookie',
headerName: 'My-Xsrf-Header',
}),
// 인터셉터 설정
withInterceptors([credentialsInterceptor])
)
]
};