即使我在请求中发送凭据,HTTP 状态代码 401

IT技术 javascript angular spring-boot cors httprequest
2021-02-06 03:34:11

最近,我向基于 Springboot 和 Angualr2 的应用程序引入了 JWT 身份验证。在那里,我尝试通过在我的 Angualr 代码中传递 JWT 令牌来执行 POST 请求

save(jobId: number, taskId: number, note: Note) {

   return this.http.post(environment.APIENDPOINT + '/jobs/' + jobId + '/tasks/' + taskId + '/notes', note, this.setHeaders()).map((response: Response) => response.json());

}

private setHeaders() {
        // create authorization header with jwt token
        let currentUser = JSON.parse(localStorage.getItem('currentUser'));
        console.log("Current token---"+ currentUser.token);
        if (currentUser && currentUser.token) {

  let headers = new Headers();
  headers.append('Content-Type', 'application/json');
  headers.append('authorization','Bearer '+ currentUser.token);
            
   let r = new RequestOptions({ headers: headers })
   return r;

        }
    }

但是在服务器端它返回状态代码 401。问题是在 Springboot 端它检查授权标头如下,它返回 null

String authToken = request.getHeader("authorization ");

然后我查看了请求标头,它在 Access-Control-Request-Headers 下具有授权标头,如下所示。但它对服务器端是不可见的。

在此处输入图片说明

然后我进一步阅读并发现这可能是 CORS 配置的问题。所以我修改了我的 CORS 配置过滤器以添加如下所示的 addExposedHeader

@Bean
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addExposedHeader("authorization");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("DELETE");

    //config.addExposedHeader("Content-Type");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}

服务器仍然抱怨它找不到授权标头。我在这里错过了什么吗?感谢你的帮助

解决方案

阅读下面的 sideshowbarker 评论后,我能够理解问题背后的基础知识。在我的项目中,我有一个 JWT 令牌过滤器,它始终检查授权标头。然后我将它修改如下,现在它按预期工作

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
try {

    if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
        response.setStatus(HttpServletResponse.SC_OK);
    }else{
        String authToken = request.getHeader(this.tokenHeader);
        jWTTokenAuthenticationService.parseClaimsFromToken(authToken);
        --
    }
    chain.doFilter(request, response);
}Catch(AuthenticationException authEx){
    SecurityContextHolder.clearContext();
    if (entryPoint != null) {
        entryPoint.commence(request, response, authEx);
    }
}

}

1个回答

您需要将服务器配置为不需要OPTIONS请求授权(即请求被发送到的服务器——而不是为您的前端代码提供服务的服务器)。

那是因为正在发生的事情是这样的:

  1. 你的代码告诉你的浏览器它想发送一个带有Authorization标题的请求
  2. 您的浏览器说,好的,带有Authorization标头的请求需要我进行 CORS 预检OPTIONS,以确保服务器允许带有Authorization标头的请求
  3. 您的浏览器将OPTIONS请求发送没有Authorizationheader的服务器,因为OPTIONS检查的全部目的是查看是否可以包含该 header。
  4. 您的服务器看到OPTIONS请求,但不是以指示它允许Authorization请求中标头的方式响应它,而是使用 401 拒绝它,因为它缺少标头。
  5. 您的浏览器期望对 CORS 预检有 200 或 204 响应,但得到的是 401 响应。所以你的浏览器就停在那里,从不尝试POST来自你的代码请求。

更多详情:

Access-Control-Request-HeadersAccess-Control-Request-Method在问题的截图请求头指示浏览器做了CORS预检OPTIONS请求

您的请求中存在AuthorizationContent-Type: application/json请求标头是触发浏览器执行 CORS 预检的原因——通过在您的代码中OPTIONS尝试POST请求之前向服务器发送请求并且因为OPTIONS预检失败,浏览器就停在那里,从不尝试POST.

因此,您必须弄清楚请求被发送到服务器上当前服务器端代码的哪一部分导致它需要对OPTIONS请求进行授权,并更改它以便它在不需要授权的情况下以OPTIONS 200 或 204 成功响应进行响应.


有关 - 启用OPTIONSSpring 服务器的具体帮助,请参阅以下答案:

我有一个 JWT 令牌过滤器,在里面它总是检查授权标头。我不得不修改该逻辑以忽略令牌过滤的 OPTION 请求并将状态设置为 200
2021-03-14 03:34:11
租户配置的CORS白名单怎么样?你怎么可能生成一个 Access-Control-Allow-Origin 标头,而不知道哪个租户,使用哪个配置,这对我来说似乎是一个疏忽......
2021-03-25 03:34:11