如何在Angular的http请求中添加授权头?

47

这是我的第一篇帖子。

我刚开始学习Go和Angular,试图将Angular应用程序连接到Go API。 我已经编写了两者,但卡在了识别问题根源上。 我以为是CORS问题,但如果我不在Angular http请求中包含头部代码行,则运行良好。此时我只想添加标头。授权代码尚未实现。

两个应用程序都在本地运行,Go应用程序在端口5000上,Angular在4200上

不起作用的Angular http请求:

this.http.get<ProjectedBalance>(requestUrl, {headers: new HttpHeaders().set('Authorization', 'my-auth-token')})
    .subscribe(data => {
     this.projBalance = data.projBalance;
   }

可行的 Angular HTTP 请求:

this.http.get<ProjectedBalance>(requestUrl)
    .subscribe(data => {
     this.projBalance = data.projBalance;
   }
我收到了这个错误:
跨域请求的响应未通过访问控制检查:所请求的资源上没有“Access-Control-Allow-Origin”标头。因此,来自“http://localhost:4200” 的来源被禁止访问。响应的HTTP状态码为403。
我在我的go代码中使用gorilla/mux和gorilla/handlers。
router := mux.NewRouter()
router.HandleFunc("/home/{endDate}", GetProjBalance).Methods("GET", "OPTIONS")
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With, Content-Type, Authorization"})
originsOk := handlers.AllowedOrigins([]string{"*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
//start server on port
log.Fatal(http.ListenAndServe(":5000", handlers.CORS(originsOk, headersOk, methodsOk)(router)))

来自 Chrome Dev Tools 的头部信息

Request URL:http://localhost:5000/home/2020-12-21
Request Method:OPTIONS
Status Code:403 Forbidden
Remote Address:[::1]:5000
Referrer Policy:no-referrer-when-downgrade

Response Headers
view source
Content-Length:0
Content-Type:text/plain; charset=utf-8
Date:Mon, 20 Nov 2017 21:39:43 GMT

Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.9,uz;q=0.8
Access-Control-Request-Headers:authorization
Access-Control-Request-Method:GET
Connection:keep-alive
Host:localhost:5000
Origin:http://localhost:4200

请考虑以问题的形式重新表述您的帖子... - maerics
我不确定为什么 handlers.CORS 不起作用,但如果你不使用CORS,你需要将开发请求代理到端口5000。在生产中,你将在端口80上运行,所以没有冲突,但由于你正在使用angular的开发服务器并在本地运行go服务器,localhost:4200localhost:5000 是不同的来源。我不确定如何以“angular 5”的方式处理这个问题,但是 webpack-dev-serverpackage.json 中有一个超级简单的 proxy 字段,你基本上想要复制它。 - bcr
你好 gobuckeyes,能否请你向我提供客户端请求 API 时在请求头中发送的列表?(可以从开发工具的网络标签页获取)另外,如果将所有3个 CORS 都设置为 {"*"},问题是否仍然存在? - Mihailo
@Mihailo 我发布了来自开发工具的标头。将所有三个CORS更改为{"*"}将错误更改为405-方法不允许。谢谢。 - gobuckeyes2
尝试将 AllowedMethods() 改回原来的状态。你的客户端应该发送两个请求,一个是使用 OPTIONS 方法,另一个是使用 GET 方法(对于这个特定的请求)。在还原 AllowedMethods 后,再次发送请求,如果错误仍然存在,请更新问题并提供 GET 请求的数据。 - Mihailo
@Mihailo 上面列出的标题是使用所示的AllowedMethods()设置返回的。我认为我发布了Options请求和Get请求。我不认为我在开发工具中看到其他请求。 - gobuckeyes2
5个回答

87

在处理 Angular > 4 中的身份验证头的最佳方式方面,最好使用 Http 拦截器 将它们添加到每个请求中,然后使用 路由守卫 Guards 来保护您的路由。

这里是我在应用程序中使用的 AuthInterceptor 的完整示例:

auth.interceptor.ts

import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';

import { Observable } from 'rxjs/Observable';

import { AuthService } from './auth.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    req = req.clone({
      setHeaders: {
        'Content-Type' : 'application/json; charset=utf-8',
        'Accept'       : 'application/json',
        'Authorization': `Bearer ${AuthService.getToken()}`,
      },
    });

    return next.handle(req);
  }
}

您需要将拦截器注册为提供者,放置在 app.module 中:

app.module.ts

import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { AuthInterceptor } from '../auth/auth.interceptor';

...

imports: [
    HttpClientModule,
    ...
],
providers: [
    {
      provide : HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi   : true,
    },
    ...
],

...

您可以在此文章中进一步了解这种方法。


关于Go方面的事情,这很可能是发送的请求标头CORS允许的标头之间不匹配的情况。首先,您应该尝试允许它们全部通过:

headersOk := handlers.AllowedHeaders([]string{"*"})
originsOk := handlers.AllowedOrigins([]string{"*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})

如果问题得到解决,请仔细地按照客户端发送的方式一个接一个地构建你的CORS


2
这个方法可以在Angular应用程序中添加头部。谢谢!对于Go部分,我能够使用这种方法。https://stackoverflow.com/questions/22452804/angularjs-http-get-request-failed-with-custom-header-alllowed-in-cors/22457910#22457910 - gobuckeyes2
太好了!很高兴我能帮到你 :) 祝你好运! - Mihailo

31

如果您不想添加拦截器,这对我起作用:

var header = {
  headers: new HttpHeaders()
    .set('Authorization',  `Basic ${btoa(AuthService.getToken())}`)
}

this.http.get(url, header)

对于Bearer,

set('Authorization',  `Bearer ${AuthService.getToken()}`)

2

Angular 6 ==> 使用授权头的HTTP Get请求示例

public IsClientCreditCardExits(companyId: string, token: any) {
    let header = new Headers({ 'Authorization': `Bearer ${token}` });
    const options = new RequestOptions({
       headers: header,
    });
    return this._http.get(this.ApiURL + "api/Subscriptions/IsClientCreditCardExits/" + companyId + "/", options);    
}

2
RequestOptions已被弃用。 - MindRoasterMir

1
这里是一个例子:

this.http
        .get(url, return new RequestOptions({
          headers: new Headers({
            Authorization: `Bearer ${authtoken}`
          }),
        }))
        .map(res => res.json());

1
以下示例适用于您仅希望在访问需要授权的资源时添加某些标头,请参见下面的代码。请注意,您需要在authentication.service.ts中创建getToken方法。
import { Injectable } from '@angular/core';
import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpEvent
} from '@angular/common/http';
import { Observable } from 'rxjs';

import { environment } from '../../environments/environment';
import { AuthenticationService } from '../services/authentication.service';

@Injectable({
  providedIn: 'root'
})
export class AuthenticationInterceptorService implements HttpInterceptor {
  constructor(public authenticationService: AuthenticationService) {}
  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    const accessToken: string = this.authenticationService.getToken();
    // set global application headers.
    request = request.clone({
      setHeaders: {
        'Content-Type': 'application/json; charset=utf-8',
        Accept: 'application/json',
        'X-AppName': environment.xAppName,
        'X-Locale': 'en'
      }
    });
    // Set headers for requests that require authorization.
    if (accessToken) {
      const authenticatedRequest = request.clone({
        headers: request.headers.set(
          'Authorization',
          `Token token=${accessToken}`
        )
      });
      // Request with authorization headers
      return next.handle(authenticatedRequest);
    } else {
      // Request without authorization header
      return next.handle(request);
    }
  }
}

app.module.ts 中注册拦截器,如下所示:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AuthenticationInterceptorService } from './services/authentication-interceptor.service';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, AppRoutingModule, HttpClientModule],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthenticationInterceptorService,
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接