【问题标题】:Authorization bearer token Angular 5授权不记名令牌Angular 5
【发布时间】:2018-09-22 22:30:39
【问题描述】:

我对如何在 Angular 5 中为简单的 Get 请求创建一个好的标头感到困惑。

这是我需要在 Angular 中做的事情:

这是我目前所拥有的:

  getUserList(): Observable<UserList[]> {
    const headers = new Headers();
    let tokenParse = JSON.parse(this.token)             
    headers.append('Authorization', `Bearer ${tokenParse}`);
    const opts = new RequestOptions({ headers: headers });  
    console.log(JSON.stringify(opts));
    const users = this.http.get<UserList[]>(this.mainUrl, opts)
    return users
            .catch(this.handleError.handleError);         
  }

这是我的 console.log 中的响应:

{"method":null,"headers":{"Authorization":["Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImYwODZlM2FiYTk0ZjVhMjVmNDhiNzlkYmI2YWUwOWY4YzE2MTUyMzg2N2I5MDZiY2MzNWQyNWJiYTZmYTE4YjEwZjA1MjZiNThkZjE2Y2FjIn0.eyJhdWQiOiJmMDExY2M1OC00MGNlLTQzYTktOGY3MS04NDI0OTRlM2E5OTciLCJqdGkiOiJmMDg2ZTNhYmE5NGY1YTI1ZjQ4Yjc5ZGJiNmFlMDlmOGMxNjE1MjM4NjdiOTA2YmNjMzVkMjViYmE2ZmExOGIxMGYwNTI2YjU4ZGYxNmNhYyIsImlhdCI6MTUyMzU1MTQ0NSwibmJmIjoxNTIzNTUxNDQ1LCJleHAiOjE1MjM1NTQ0NDUsInN1YiI6IjIiLCJzY29wZXMiOlsiYXV0aGVudGljYXRlZCIsImFuZ3VkcnUiXX0.E-WdQTl7nPDW0gj0rohfql-QgnAinzvDxPR-pySMrG07XFY9tA6Ex7IL23pDBmKDmQO8RcZKa0L5r6SRQq9_iqzMWzn5Zxp94J9TJrpZ2KGMoLR_FbK_tpC5G5q5vUnCe3q34sH7cPdT_2cI704OWWaYmIUKKpXWUIG0PJw_uKSJ_uOifPv59RZGQkoaQ9gPywDKe-uamm1Faug-Kk2YnFMoEJq7ou19zyxgdpX80ZTPUae67uB0PGLRuvxfGaqVsJ8k0NunAY3-pyUnBwR_3eeuOxf4TyfW2aiOJ9kuPgsfV4Z1JD7nMpNtTHMJaXEyNkBW8RlYHD1pj4dkdnsDmw"]},"body":null,"url":null,"withCredentials":null,"responseType":null}

看起来很漂亮。但是给了我这个错误

GET http://druang.dd:8080/user-list?_format=json403(禁止)

还有另一个线索可以解开这个谜团。在 Sublime 文本中,如果我将鼠标放在 opts 上,它会说:

src/app/services/userlist.service.ts(33,59) 中的错误:错误 TS2345: 'RequestOptions' 类型的参数不可分配给 输入'{标头?:HttpHeaders | { [标题:字符串]:字符串 |细绳[]; };观察?:“身体”;参数?:Ht...'。属性“标题”的类型 不兼容。 类型 'Headers' 不可分配给类型 'HttpHeaders | { [标题:字符串]:字符串 |细绳[]; }'。 类型 'Headers' 不可分配给类型 '{ [header: string]: string |细绳[]; }'。 “标头”类型中缺少索引签名。

有什么想法吗?? 这是完整的Git repo 感谢您的帮助!

【问题讨论】:

  • 我认为您为 Headers 导入了错误的类尝试检查版本 5 中的 Angular 文档 http 服务已被 httpClient 服务弃用,但 httpClient 位于 @angular/common 中,另一个位于 @ angular/http 你不能混合这些类,因为它会导致错误。对我来说,您的错误看起来像是使用来自“@angular/common”的 http 和来自“@angular/http”的标头,而不是来自“@angular/common”的 HttpHeaders
  • 嗨,谢谢@Nicu,这是我的导入:import { HttpClient, HttpHeaders } from '@angular/common/http'; 根据角度documentation
  • 太棒了 :D @angular/http 它将被替换为 @angular/common/http 我想在 ng 6 中删除。

标签: angular header authorization bearer-token


【解决方案1】:

我建议使用HttpInterceptor 为传出请求设置默认 HTTP 标头,而不是为每个调用添加额外的 HTTP 标头。

HTTP Client - Setting default headers @ angular.io


在您的示例中,您可以执行以下操作:

import { Http, Headers, Response } from '@angular/http';

getLoggedInUser(auth_token): Observable<any> {
  const headers = new Headers({
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${auth_token}`
  })
  return this.http.get(apiUrl, { headers: headers })
}

【讨论】:

  • 只是补充一下,令牌应该在前面加上'Bearer',所以在你的例子中,它将是'Authorization':Bearer ${auth_token}
  • 我需要使用 HttpHeaders 而不是 Headers,但之后一切正常。 ?
  • 只是好奇,是用`符号来组合文字吗?
【解决方案2】:

对于get 请求,我使用了以下代码,它可以工作

import { HttpClient, HttpHeaders } from '@angular/common/http';

getServerList(){
    var reqHeader = new HttpHeaders({ 
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + JSON.parse(localStorage.getItem('mpManagerToken'))
     });
    return this.http.get<Server[]>(`${environment.apiUrl}/api/Servers/GetServerList`, { headers: reqHeader });
}

【讨论】:

    【解决方案3】:

    两件事:

    1. headers.append(...) 不会改变标头对象,因此不会发送您的授权标头。你需要做headers = headers.append(...)

    2. 试试this.http.get&lt;UserList[]&gt;(this.mainUrl, { headers: headers });

    【讨论】:

    • 1) headers = headers.append给我:无法分配标头,因为它是常量或只读属性
    • 要么将声明从 const headers 更改为 let headers`,要么执行 const headers = new Headers().append('Authorization', Bearer ${tokenParse}`);
    • let 说:Type void is not assignable to type 'Headers'
    • 另一个选项有效,但是当我设置 const opts = new RequestOptions({ headers: headers }); 时,我得到了:ERROR in src/app/services/userlist.service.ts(33,37): error TS2345: Argument of type '{ headers: void; }' is not assignable to parameter of type 'RequestOptionsArgs'. Types of property 'headers' are incompatible. Type 'void' is not assignable to type 'Headers'.
    • 另外,如果我忘记了选项,直接转到http get请求中的{headers:headers},我得到了这个:ERROR in src/app/services/userlist.service.ts(35,59): error TS2345: Argument of type '{ headers: void; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'. Types of property 'headers' are incompatible. Type 'void' is not assignable to type 'HttpHeaders | { [header: string]: string | string[]; }'.
    【解决方案4】:

    在 Angular 6 和 7 中,此方法可用于拦截所有 HTTP 请求并添加不记名令牌。

    实施教程可在此处获得。 Youtube,本频道有教程。

    拦截器组件

    import {
      HttpInterceptor,
      HttpRequest,
      HttpHandler,
      HttpUserEvent,
      HttpEvent
    } from '@angular/common/http';
    import { Observable } from 'rxjs';
    import { UserService } from '../shared/user.service';
    import { tap } from 'rxjs/operators';
    import { Injectable } from '@angular/core';
    import { Router } from '@angular/router';
    
    @Injectable()
    export class AuthInterceptor implements HttpInterceptor {
      constructor(private router: Router) {}
    
      intercept(
        req: HttpRequest<any>,
        next: HttpHandler
      ): Observable<HttpEvent<any>> {
        if (req.headers.get('No-Auth') === 'True') {
          return next.handle(req.clone());
        }
    
        if (localStorage.getItem('userToken') != null) {
          const clonedreq = req.clone({
            headers: req.headers.set(
              'Authorization',
              'Bearer ' + localStorage.getItem('userToken')
            )
          });
          return next.handle(clonedreq).pipe(
            tap(
              succ => {},
              err => {
                if (err.status === 401) {
                  // this.router.navigateByUrl('/login');
                } else if ((err.status = 403)) {
                  // this.router.navigateByUrl('/forbidden');
                  // alert(err.localStorage.getItem('userToken'));
                }
              }
            )
          );
        } else {
          this.router.navigateByUrl('/login');
        }
      }
    }
    

    守护组件

    import { Injectable } from '@angular/core';
    import {
      CanActivate,
      ActivatedRouteSnapshot,
      RouterStateSnapshot,
      Router
    } from '@angular/router';
    import { Observable } from 'rxjs';
    import { UserService } from '../shared/user.service';
    import { ToastrService } from 'ngx-toastr';
    
    @Injectable()
    export class AuthGuard implements CanActivate {
      constructor(
        private router: Router,
        private userService: UserService,
        private toastr: ToastrService
      ) {}
      canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
      ): boolean {
        if (localStorage.getItem('userToken') != null) {
          const roles = next.data['roles'] as Array<string>;
          if (roles) {
            const match = this.userService.roleMatch(roles);
            if (match) {
              return true;
            } else {
              // tslint:disable-next-line: quotemark
              this.toastr.info("You don't have access to this page");
              this.router.navigate(['/login']);
              // this.router.navigate(['/forbidden']);
              return false;
            }
          } else {
            return true;
          }
        }
        this.router.navigate(['/login']);
        return false;
      }
    }
    

    将其添加到 app.modules.ts

    providers: [
        ConfirmationDialogService,
        UserService,
        DoctorService,
        { provide: OwlDateTimeIntl, useClass: DefaultIntl },
        { provide: OWL_DATE_TIME_FORMATS, useValue: MY_MOMENT_FORMATS },
        AuthGuard,
        {
          provide: HTTP_INTERCEPTORS,
          useClass: AuthInterceptor,
          multi: true
        }
      ],
    

    然后将守卫添加到路由中

     {
        path: 'adminPanel',
        component: AdminPanelComponent,
        canActivate: [AuthGuard],
        data: { roles: ['Admin'] }
      },
    

    【讨论】:

      【解决方案5】:

      我不是很擅长编程,但有一点尝试和失败 如果发现这个:

        getUserList(): Observable<UserList[]> {
          let tokenParse = JSON.parse(this.token)    
          // let myHeaders = new Headers();
          // myHeaders.set('Authorization', `Bearer ${tokenParse}`);
          // let options = new RequestOptions({ headers: myHeaders});
          const users = this.http.get<UserList[]>(this.mainUrl, { headers:new HttpHeaders().append('Authorization', `Bearer ${tokenParse}`)})
          // const users = this.http.get<UserList[]>(this.mainUrl, options);
          return users
                  .catch(this.handleError.handleError);         
        }
      

      我使用.set.append 并不重要,归根结底,这两种情况都适用...

      我真的不知道发生了什么,所以,如果有人想在 cmets 中解释它,欢迎您...

      【讨论】:

        【解决方案6】:

        我已使用上述所有建议的格式来附加带有访问令牌的标头,它在请求标头中添加了 null,例如“Authorization Bearer null”。 如果我在添加/克隆标题行之前打印 accesstoken,则在浏览器控制台中打印 accesstoken 值。这是我使用的格式。

        console.log("Inside Interceptor accesstoken : " + this.oauthService.getAccessToken());
            req = req.clone({
              setHeaders: {
                 Authorization: 'Bearer ' +  this.oauthService.getAccessToken()
              }
            });
            return next.handle(req);
        

        【讨论】:

          【解决方案7】:
          'Authorization': 'Bearer ' + access_token,
          

          成功了

          【讨论】:

            【解决方案8】:

            虽然@HassanRahman 为get 请求显示它,但对于post 请求,

            import { HttpClient, HttpHeaders } from '@angular/common/http';
            
            getServerList(){
            
                postData = { your data }
                var reqHeader = new HttpHeaders({ 
                    'Content-Type': 'application/json',
                    'Authorization': 'Bearer ' + JSON.parse(localStorage.getItem('mpManagerToken'))
                 });
                return this.http.post<Server[]>(`${environment.apiUrl}/api/Servers/GetServerList`, postData, { headers: reqHeader });
            }
            

            【讨论】:

            • 在我看来非常重要的答案,我不知道为什么投反对票。在我的情况下,我在服务器上发布了没有参数的方法,所以有this.router.post&lt;string&gt;('https://localhost:5001/api/method', null, {headers: { 'Authorization': `Bearer ${localStorage.getItem('authToken')}`, }}) .subscribe(data =&gt; { //now use data window.location.href = data; }); 当然最好使用拦截器,但我认为使用postget 查看像这样的简单基本示例也很重要.
            • @LazarĐorđević 感谢您的评论
            猜你喜欢
            • 1970-01-01
            • 2019-05-28
            • 2021-01-01
            • 2018-07-26
            • 2020-07-09
            • 2018-02-07
            • 2021-06-27
            • 2021-08-02
            • 2018-09-22
            相关资源
            最近更新 更多