授权不记名令牌Angular 5

Posted

技术标签:

【中文标题】授权不记名令牌Angular 5【英文标题】:Authorization bearer token 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 中删除。 【参考方案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】:

两件事:

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

    试试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ć 感谢您的评论

以上是关于授权不记名令牌Angular 5的主要内容,如果未能解决你的问题,请参考以下文章

确定不记名令牌是不是已过期或刚刚被授权

授权:不记名令牌与 AWS 的令牌授权方相同吗?

Firebase 授权不记名令牌未注册

Angular 7 自动刷新不记名令牌

邮递员上的授权类型不记名令牌和来自 API 的请求数据,这需要带有颤振的令牌不记名

使用不记名令牌进行身份验证(≠ 授权)