添加Auth0令牌后调用API Gateway时出现CORS错误
AWS全栈Web应用CORS错误求助
环境说明
- 前端:Angular应用,托管于S3+CloudFront,使用Route53配置自定义域名
- 后端:TypeScript Express服务,部署在API Gateway之后,采用Auth0认证,基于Auth0官方示例项目开发
问题现象
未被Auth0拦截器处理的请求可正常响应,但完成Auth0登录后,发送被拦截器附加令牌的请求时触发CORS错误:
Access to XMLHttpRequest at 'https://api-gateway.com/dev/api/messages/protected' from origin 'https://website.link' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
相关代码
Angular Auth模块拦截器配置
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AuthModule, AuthHttpInterceptor } from '@auth0/auth0-angular'; import { environment as env } from '../environments/environment'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { SharedModule } from './shared'; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, AppRoutingModule, SharedModule, HttpClientModule, AuthModule.forRoot({ ...env.auth0, httpInterceptor: { allowedList: [`${env.api.serverUrl}/api/messages/admin`, `${env.api.serverUrl}/api/messages/protected`], //allowedList: [`${env.api.serverUrl}/api/messages/admin`], }, }), ], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true, }, ], bootstrap: [AppComponent], }) export class AppModule {}
Express后端核心配置
import cors from "cors"; import * as dotenv from "dotenv"; import * as awsServerlessExpress from 'aws-serverless-express'; import express from "express"; import helmet from "helmet"; import nocache from "nocache"; import { messagesRouter } from "./messages/messages.router"; import { errorHandler } from "./middleware/error.middleware"; import { notFoundHandler } from "./middleware/not-found.middleware"; dotenv.config(); if (!(process.env.PORT && process.env.CLIENT_ORIGIN_URL)) { throw new Error( "Missing required environment variables. Check docs for more info." ); } const PORT = parseInt(process.env.PORT, 10); const CLIENT_ORIGIN_URL = process.env.CLIENT_ORIGIN_URL; const app = express(); const apiRouter = express.Router(); app.use(express.json()); app.set("json spaces", 2); app.use( helmet({ hsts: { maxAge: 31536000, }, contentSecurityPolicy: { useDefaults: false, directives: { "default-src": ["'none'"], "frame-ancestors": ["'none'"], }, }, frameguard: { action: "deny", }, }) ); app.use((req, res, next) => { res.contentType("application/json; charset=utf-8"); next(); }); app.use(nocache()); app.use( cors({ origin: CLIENT_ORIGIN_URL, methods: ["GET", "POST", "PUT", "DELETE"], allowedHeaders: ["Authorization", "Content-Type"], maxAge: 86400, }) ); app.use("/api", apiRouter); apiRouter.use("/messages", messagesRouter); app.use(errorHandler); app.use(notFoundHandler); // create serverless express const server = awsServerlessExpress.createServer(app); // export the handler function for AWS Lambda export const handler = (event: any, context: any) => awsServerlessExpress.proxy(server, event, context);
尝试过的路由级CORS配置
messagesRouter.get("/protected", validateAccessToken, (req, res) => { res.set("Access-Control-Allow-Origin", CLIENT_ORIGIN_URL); try { logger.info(JSON.stringify(req.auth)); logger.info(`Token: ${JSON.stringify(req.auth?.token)}`) //console.log(req.auth?.token) const message = getProtectedMessage(); res.status(200).json(message); } catch (err){ console.log(err); res.status(500).json('Error') } });
尝试过的其他CORS全局配置
app.use(cors());
app.use(cors({ origin: CLIENT_ORIGIN_URL, methods: ["GET", "POST", "PUT", "DELETE"], allowedHeaders: ["Authorization", "Content-Type"], credentials: true, }));
CloudFront Terraform配置
resource "aws_cloudfront_distribution" "website_distribution" { origin { domain_name = aws_s3_bucket.frontend_bucket.bucket_regional_domain_name origin_id = aws_s3_bucket.frontend_bucket.id s3_origin_config { origin_access_identity = aws_cloudfront_origin_access_identity.oai.cloudfront_access_identity_path } } origin { domain_name = replace(aws_api_gateway_deployment.example.invoke_url, "/^https?://([^/]*).*/", "$1") origin_id = aws_api_gateway_deployment.example.id origin_path = "/${terraform.workspace}" custom_origin_config { http_port = 80 https_port = 443 origin_protocol_policy = "https-only" origin_ssl_protocols = ["TLSv1", "TLSv1.1", "TLSv1.2"] } } default_cache_behavior { allowed_methods = ["GET", "HEAD", "OPTIONS", "POST", "DELETE", "PUT", "PATCH"] cached_methods = ["GET", "HEAD", "OPTIONS"] target_origin_id = aws_s3_bucket.frontend_bucket.id forwarded_values { query_string = false cookies { forward = "none" } } viewer_protocol_policy = "redirect-to-https" min_ttl = 0 default_ttl = 3600 max_ttl = 86400 } ordered_cache_behavior { path_pattern = "/api/*" target_origin_id = aws_api_gateway_deployment.example.id allowed_methods = ["GET", "HEAD", "OPTIONS", "POST", "DELETE", "PUT", "PATCH"] cached_methods = ["GET", "HEAD", "OPTIONS"] forwarded_values { query_string = true cookies { forward = "none" } headers = ["Authorization"] } viewer_protocol_policy = "redirect-to-https" min_ttl = 0 default_ttl = 3600 max_ttl = 86400 } restrictions { geo_restriction { restriction_type = "none" locations = [] } } viewer_certificate { acm_certificate_arn = aws_acm_certificate.cert.arn ssl_support_method = "sni-only" minimum_protocol_version = "TLSv1.2_2018" cloudfront_default_certificate = false } custom_error_response { error_code = 403 response_page_path = "/index.html" response_code = "200" error_caching_min_ttl = 300 } enabled = true is_ipv6_enabled = true http_version = "http2" price_class = "PriceClass_100" default_root_object = "index.html" aliases = [var.domain_name[terraform.workspace], "www.${var.domain_name[terraform.workspace]}"] }
请求协助解决该CORS错误。
内容的提问来源于stack exchange,提问作者Garrett James
相关产品推荐
相关产品推荐

