首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >跟踪如何修复CORS问题

跟踪如何修复CORS问题
EN

Stack Overflow用户
提问于 2019-07-29 20:32:02
回答 2查看 4.1K关注 0票数 6

在我正在处理的申请中,我遇到了一个CORS问题。

它是在Kubernetes中安装的,有一个第三方Java框架:

http://www.ninjaframework.org/

我得到了以下错误:

代码语言:javascript
复制
Preflight response is not successful
XMLHttpRequest cannot load https://api.domain.com/api/v1/url/goes/here? due to access control checks.
Failed to load resource: Preflight response is not successful

我不认为问题在库伯内特斯,但只是以防万一-这是我的库伯内特斯设置:

代码语言:javascript
复制
apiVersion: v1
kind: Service
metadata:
  name: domain-server
  annotations:
    dns.alpha.kubernetes.io/external: "api.domain.com"
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-2:152660121739:certificate/8efe41c4-9a53-4cf6-b056-5279df82bc5e
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
spec:
  type: LoadBalancer
  selector:
    app: domain-server
  ports:
    - port: 443
      targetPort: 8080
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: domain-server
spec:
  replicas: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 3
  revisionHistoryLimit: 10
  template:
    metadata:
      labels:
        app: domain-server
    spec:
      containers:
        - name: domain-server
          image: "location.aws.etc"
          imagePullPolicy: Always
    ...

我完全迷失在这里--如何在api端点上启用CORS?很抱歉,如果这是一个简单的问题,或者我没有提供足够的信息,但我不知道如何做到这一点,我尝试了几个途径。

注意,我要说的是,api.domain.com是我的实际api域的替代品,我只是不想透露我在上工作的站点

编辑:

我猜这可能与此有关:

代码语言:javascript
复制
private Result filterProtectedApi(FilterChain chain, Context context, boolean isMerchant, JwtAuthorizer jwtAuthorizer) {
    String authHeader = context.getHeader("Authorization");
    if (authHeader == null || !authHeader.startsWith("Bearer ")) {
        return this.forbiddenApi();
    }
    context.setAttribute("access-token", authHeader.substring("Bearer ".length()));
    return this.filterProtected(chain, context, isMerchant, jwtAuthorizer, parser -> parser.parseAuthHeader(authHeader), this::forbiddenResource);
}

private AuthLevel getAuthLevel(String requestPath) {
    log.info("REQUEST PATH: " + requestPath);
    if (requestPath.equals("/auth") || requestPath.equals("/auth/merchant") || requestPath.equals("/auth/app")
            || requestPath.startsWith("/assets/") || requestPath.equals("/privacy-policy.html")
            || requestPath.equals("/forbidden.html") || requestPath.equals("/favicon.ico")
            || requestPath.startsWith("/invite/ios/") || requestPath.startsWith("/stripe/")
            || requestPath.startsWith("/chat")) {
        return AuthLevel.UNPROTECTED_RESOURCE;
    }
    if (requestPath.startsWith("/merchant/api/")) {
        return AuthLevel.PROTECTED_MERCHANT_API;
    }
    if (requestPath.startsWith("/merchant/")) {
        return AuthLevel.PROTECTED_MERCHANT_RESOURCE;
    }
    if (requestPath.startsWith("/api/")) {
        return AuthLevel.PROTECTED_API;
    }
    return AuthLevel.PROTECTED_RESOURCE;
}

我尝试过添加一些忽略选项请求的内容,但是我仍然没有通过飞行前的检查。

代码语言:javascript
复制
private Result filterProtectedApi(FilterChain chain, Context context, boolean isMerchant,
        JwtAuthorizer jwtAuthorizer) {
    if (context.getMethod().toLowerCase().equals("options")) {
        return chain.next(context);
    }
    String authHeader = context.getHeader("Authorization");
    if (authHeader == null || !authHeader.startsWith("Bearer ")) {
        return this.forbiddenApi();
    }
    context.setAttribute("access-token", authHeader.substring("Bearer ".length()));
    return this.filterProtected(chain, context, isMerchant, jwtAuthorizer,
            parser -> parser.parseAuthHeader(authHeader), this::forbiddenResource);
}

试飞前检查成功需要做些什么?

编辑-根据以下建议将其更改为此:

代码语言:javascript
复制
@Override
public Result filter(FilterChain chain, Context context) {
    if (context.getMethod().toLowerCase().equals("options")) {
        return Results.html().addHeader("Access-Control-Allow-Origin", "*")
                .addHeader("Access-Control-Allow-Headers", "Authorization")
                .addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS").render("OK");
    }
    AuthLevel authLevel = this.getAuthLevel(context.getRequestPath());
    switch (authLevel) {
    case PROTECTED_API: {
        return this.filterProtectedApi(chain, context, false, this.jwtAuthorizer);
    }
    case PROTECTED_MERCHANT_RESOURCE: {
        return this.filterProtectedResource(chain, context, "merchant-access-token", "/auth/merchant", true,
                this.merchantJwtAuthorizer);
    }
    case PROTECTED_MERCHANT_API: {
        return this.filterProtectedApi(chain, context, true, this.merchantJwtAuthorizer);
    }
    case UNPROTECTED_RESOURCE: {
        return this.filterUnprotectedResource(chain, context);
    }
    }
    return this.filterProtectedResource(chain, context, "access-token", "/auth", false, this.jwtAuthorizer);
}
EN

回答 2

Stack Overflow用户

发布于 2019-08-01 15:10:52

您在正确的路径上,试图在auth验证之前忽略选项请求

代码语言:javascript
复制
if (context.getMethod().toLowerCase().equals("options")) {
    return chain.next(context);
}

此外,需要的是对飞行前请求作出正确的响应。

代码语言:javascript
复制
if (context.getMethod().toLowerCase().equals("options")) {
    return Results.html()
                  .addHeader("Access-Control-Allow-Origin", "*")
                  .addHeader("Access-Control-Allow-Headers", "Authorization")
                  .addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE")
                  .render("OK");
}

简而言之,你需要用

  • 适当的http状态代码,通常为200或204
  • 添加所需的http响应头
    • 带有"*“的"Access-Control-Allow-Origin"允许来自所有域的CORS,或者只允许来自特定域的"http://www.domainA.com"
    • 允许"Access-Control-Allow-Headers",http报头
    • 允许"Access-Control-Allow-Methods",http方法

  • 响应体是不相关的,你可以只发送“确定”。

请注意,可以从(任何路由)执行飞行前请求,因此我建议使用上面的代码创建一个新的过滤器,并在所有路由之前使用它。

所以在实现过滤器()方法之后使用它

代码语言:javascript
复制
public Result filter(FilterChain chain, Context context) {
     if (context.getMethod().toLowerCase().equals("options")) {
          return Results.html()
                  .addHeader("Access-Control-Allow-Origin", "*")
                  .addHeader("Access-Control-Allow-Headers", "Authorization")
                  .addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE")
                  .render("OK");
     }

Kubernetes Ingress的CORS

尝试在注释配置中启用:

代码语言:javascript
复制
annotations:
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS"
    nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:8100"
    nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
    nginx.ingress.kubernetes.io/cors-allow-headers: "authorization"

请注意,字符串"*“不能用于支持凭据(https://www.w3.org/TR/cors/#resource-requests)的资源,请尝试使用域列表(逗号分隔)而不是*。

参考文献:

票数 5
EN

Stack Overflow用户

发布于 2019-08-03 08:49:21

你实际上是把两件事混合在一起。访问控制和跨源请求。

跨源请求可以由Kubernetes直接处理。您需要适当地配置您的入口,以正确地转发跨源请求。无需在应用程序中配置任何内容。有关示例配置,请参见这里

但是,访问控制(身份验证和授权)需要在应用程序级别进行处理,为此可以使用此类筛选器。如果您对某些功能使用选项,则只需要对其进行处理和实现。我个人的建议是直接过滤这些请求。

如果您将跨源/代理请求和访问控制混合在一起,您将始终面临一个或另一个问题。让各个模块做他们应该做的事情,这样就更容易调试和管理。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57260996

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档