Angular 6 - Why is Bearer Token missing in product

2020-06-07 06:46发布

I'm using Angular 6 with an HTTP Interceptor configured to apply bearer token to outgoing requests.

  • In the dev build (ng serve), the token is applied and everything works fine. :-)

  • In the production build (ng serve --prod) the request is sent out without bearer token. :-(

In the prod build, I have verified the header is being applied, by dumping the headers to the console after applying them.

I have no idea why they are excluded from the http request.

There are NO differences in my environment files.

What else should I be looking at?

missing bearer token

What can I do to fix this?

At first I thought this was an issue between my local environment and my staging environment, but then I tried running ng serve --prod locally and saw the same results.

All that to say, everything is identical except one being a production build and one being a dev build.

jwt-interceptor:

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

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        // add authorization header with jwt token if available
        let currentUser = JSON.parse(localStorage.getItem('currentUser'));

        if (currentUser && currentUser.token) {
            request = request.clone({
                setHeaders: {
                    Authorization: `Bearer ${currentUser.token}`
                }
            });
            console.log('headers:', request.headers); // <---- I can see headers in console output
        }

        return next.handle(request);
    }
}

Here's what I see in the console: screenshot of console output

app.module.ts

import { HttpClientModule, HttpClient, HttpInterceptor } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { PortalModule } from '@angular/cdk/portal';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { JwtInterceptor } from './jwt-interceptor';
import { ENV } from '../environments/environment';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
... 
import { myApiService } from './services/my-api.service';
import { myModalComponent } from './_components/my-modal/my-modal.component';
import { myModalService } from './services/my-modal.service';

import { AngularLaravelEchoModule, PusherEchoConfig, EchoInterceptor } from 'angular-laravel-echo/angular-laravel-echo';

export const echoConfig: PusherEchoConfig = {
    userModel: 'App.User',
    notificationNamespace: 'App\\Notifications',
    options: {
        broadcaster: 'pusher',
        key: ENV.pusherConfig.key,
        cluster: ENV.pusherConfig.cluster,
        host: ENV.apiRoot,
        authEndpoint: ENV.apiRoot + '/broadcasting/auth',
    }
};

@NgModule({
    declarations: [
        AppComponent,
        ...
    ],
    imports: [
        BrowserModule,
        HttpClientModule,
        BrowserModule,
        AppRoutingModule,
        FormsModule,
        ReactiveFormsModule,
        PortalModule,
        AngularLaravelEchoModule.forRoot(echoConfig)
    ],
    providers: [
        myApiService,
        myModalService,
        {
            provide: HTTP_INTERCEPTORS,
            useClass: JwtInterceptor,
            multi: true,
        },
        {
            provide: HTTP_INTERCEPTORS,
            useClass: EchoInterceptor,
            multi: true
        }
    ],
    bootstrap: [AppComponent],
    entryComponents: [ 
        myModalComponent
    ]
})

export class AppModule {
}

6条回答
Juvenile、少年°
2楼-- · 2020-06-07 06:52

I wrote this app in StackBlitz, and it's working fine when I run it locally with ng serve --prod.

https://stackblitz.com/edit/angular-yzckos

Download it and run it to see if you're still getting undefined in your network tab. If you can see the header properly being sent, then there's definitely something funny in your code.

Try bellow :

1- try running `ng serve --port=aDifferentPort // like 2098

Maybe there's something running on that port and sending auth header

2- Try with AOT false, can't think of why that would cause any issue

3- Make sure your browser doesn't have any extension that overrides the Auth header or try other browsers

4- Turn off your other HTTP interceptors, maybe one of them does something unexpected

5- Change the header name from Authorizaion to MyAuthorization, see if you're still getting undefined, if you don't, then it's being overridden by a something, check your package.json and make sure you're not running anything else on the production serve.

6- Turn off the JwtInterceptor altogether and try attaching the authorization header to your HTTP request, see if you're still getting undefined.

7- If none helped, you really need to send more code to us :)

查看更多
Emotional °昔
3楼-- · 2020-06-07 06:55

Try this

if (currentUser && currentUser.token) {
        request = request.clone({
            setHeaders: {
                Authorization: `Bearer ${currentUser.token}`
            }
        });
        console.log('headers:', request.headers); // <---- I can see headers in console output
    }
if (typeof $ != 'undefined') {
    $.ajaxSetup({
      beforeSend: function (xhr: any) {
        xhr.setRequestHeader('Authorization', 'Bearer ' + currentUser.token);
      }
    });
  }
    return next.handle(request);
查看更多
做个烂人
4楼-- · 2020-06-07 06:56

I have had almost the similar issue in the production environment where server completely ignores the Authorization header. Angular 6 sends the Authorization header properly but server strips out completely (Due to most of production server, shared hosting security settings). I know this might not be the answer you looking for. But, I just wanted give you a clue.

So, finally for me to get this working, I had to use a different header parameter such as Php-Auth-Digest, like this.

request = request.clone({
    setHeaders: {
      "Php-Auth-Digest": `Bearer ${currentUser.token}`,
    }
  });

As a workaround try changing your header parameter name.

Cheers!

查看更多
孤傲高冷的网名
5楼-- · 2020-06-07 07:02

You can try cloning the headers manually in your request.clone() method. This is what works for me:

export class HttpHeaderInterceptor implements HttpInterceptor {
  // ...
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // ...
    const clonedRequest = req.clone({ 
      headers: req.headers.set('Authorization', 'Bearer ' + currentUser.token) 
    });
    return next.handle(clonedRequest).pipe(
      catchError(err => { /* Error handling here */ })
    );
  }
}

Hope this helps a little :-)

查看更多
再贱就再见
6楼-- · 2020-06-07 07:07

I have an idea about this - but I'm not sure it might work or not please check

HttpHeaders are mutable, if you add any header it updates the existing one and appends the value - so this cause me a problem in appending a header so followed the below method:

private getHeaders(): HttpHeaders {
    let headers = new HttpHeaders();
    headers = headers.append("Content-Type", "application/json");
    return headers;
  }

Since, I append the new headers and assigned the object to the original object and returned the object - This worked for me fine in both prod and dev build

But in your case you can use the same method above in your HttpInterceptor or try to change the setheaders with headers as below mentioned sample

if (currentUser && currentUser.token) {
            request = request.clone({
                headers: new HttpHeaders({
                    Authorization: `Bearer ${currentUser.token}`
                })
            });
            console.log('headers:', request.headers); 
        }

I'm sure this will solve your problem in both the builds - try and let me know if it doesn't work - Hope it works thanks - happy coding !!

查看更多
Rolldiameter
7楼-- · 2020-06-07 07:12

Can you try setting the header in the actual api call? Like, example:

put(path: string, body: Object = {}): Observable<any> {
return this.http.put(`${environment.api_url}${path}`, body, { headers: 
     this.setHeaders() })
     .map((res: Response) => {
        return res;
     });
}

private setHeaders(): HttpHeaders {
    const headersConfig = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Authorization': 'Bearer ' + this.oauthService.getAccessToken()
    };
    return new HttpHeaders(headersConfig);
}

And interceptor will have just the

request.clone() 
查看更多
登录 后发表回答