简体   繁体   English

如何将 firebase jwt getIdToken 发送到 http 获取 ZD18B8624A0F5F721DA7B8235Z 中的请求

[英]How to send firebase jwt getIdToken to http get request in angular 8?

I am using angular 8 to make a SPA.我正在使用 angular 8 制作 SPA。

Firebase is used to authenticate the user both in the client as well as in the backend, so I need to send the jwt token in http.get request to the backend to authenticate the user. Firebase 用于在客户端和后端对用户进行身份验证,因此我需要将 http.get 中的 jwt 令牌发送到后端以进行身份验证请求。

Backend is an API made with django 2.2 and django rest framework which sends the api to be consumed in client application. Backend is an API made with django 2.2 and django rest framework which sends the api to be consumed in client application.

auth.service.ts auth.service.ts

@Injectable({
  providedIn: 'root'
})

export class AuthService {
  userData: any; // Save logged in user data
  public userToken: string;

  constructor(
    public afs: AngularFirestore,   // Inject Firestore service
    public afAuth: AngularFireAuth, // Inject Firebase auth service
    public router: Router,
    public ngZone: NgZone // NgZone service to remove outside scope warning
  ) {
    /* Saving user data in localstorage when 
    logged in and setting up null when logged out */
    this.afAuth.authState.subscribe(user => {
      if (user) {
        this.userData = user;
        localStorage.setItem('user', JSON.stringify(this.userData));
        JSON.parse(localStorage.getItem('user'));
      } else {
        localStorage.setItem('user', null);
        JSON.parse(localStorage.getItem('user'));
      }
    });

  }


  GetToken(): string {
    this.afAuth.auth.onAuthStateChanged( user => {
      if (user) {
        user.getIdToken().then(idToken => {
          this.userToken = idToken;

            // this shows the userToken
          console.log('token inside getToken method ' + this.userToken);
        });
      }
    });

    // this shows userToken as undefined
    console.log('before return ' + this.userToken);
    return this.userToken;
  }

}

api.service.ts api.service.ts

@Injectable({
  providedIn: 'root'
})
export class ApiService {

  private url = environment.baseUrl;
  token: any;
  data: any;

  constructor(
    private http: HttpClient,
    private authService: AuthService,
    ) {}



    // old method to get emloyees data
  // public getEmployees(): Observable<Employee[]> {
  //   return this.http.get<Employee[]>(`${this.url}/employee/`);
  // }


  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json',
      'Authorization': 'JWT ' + this.authService.GetToken()
    }),
  };


  public getEmployees(): Observable<Employee[]> {

      // token is undefined here
    console.log('token inside getEmployees method ' + this.token);

    return this.http.get<Employee[]>(`${this.url}/employee/`, this.httpOptions);
  }

}

The backend is working perfectly which I verified by adding the token in the httpOptions, like so:后端工作正常,我通过在 httpOptions 中添加令牌验证了这一点,如下所示:

httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json',
      'Authorization': 'JWT ' + 'ey.....'
    }),
  };

But when I try doing the same as given in code it doesn't work.但是当我尝试做与代码中给出的相同的事情时,它不起作用。 The user token remains undefined.用户令牌仍未定义。

Peter's answer has the crux of it: getIdToken() is asynchronous, so by the time your return this.userToken;彼得的答案有关键: getIdToken()是异步的,所以当你return this.userToken; runs, the this.userToken = idToken;运行, this.userToken = idToken; hasn't run yet.还没跑。 You should be able to see this from the output of your console.log statements.您应该能够从您的console.log语句的 output 中看到这一点。

For more on this see How to return value from an asynchronous callback function?有关这方面的更多信息,请参阅如何从异步回调 function 中返回值? I highly recommend studying this answer for a while, as this asynchronous behavior is incredibly common when dealing with web APIs.我强烈建议研究这个答案一段时间,因为这种异步行为在处理 web API 时非常普遍。

The fix for your code is to return a Promise , instead of trying to return the value:您的代码的修复是返回Promise ,而不是尝试返回值:

GetToken(): Promise<string> {
  return new Promise((resolve, reject) => {
    this.afAuth.auth.onAuthStateChanged( user => {
      if (user) {
        user.getIdToken().then(idToken => {
          this.userToken = idToken;
          resolve(idToken);    
        });
      }
    });
  })
}

In words: GetToken returns a promise that resolves once an ID token is available.换句话说: GetToken返回一个 promise,一旦 ID 令牌可用,它就会解析。 If you know the user is already signed in when you call this function, you can simplify it to:如果您在调用此 function 时知道用户已经登录,则可以将其简化为:

GetToken(): string {
    const user = firebase.authentication().currentUser;
    return user.getIdToken()
}

The difference is that the second function does not wait for the user to be signed in, so will fail if there is no signed in user.不同的是,第二个 function 不等待用户登录,所以如果没有登录用户会失败。

You then use either of the above functions like this in getEmployees :然后,您可以在getEmployees中使用上述任一函数:

public getEmployees(): Observable<Employee[]> {
  return new Promise((resolve, reject) => 
    this.authService.GetToken().then((idToken) => {
      httpOptions = {
        headers: new HttpHeaders({
          'Content-Type': 'application/json',
          'Authorization': 'JWT ' + idToken
        }),
      };

      this.http.get<Employee[]>(`${this.url}/employee/`, this.httpOptions)
          .then(resolve).catch(reject);

    })
  })
}

It is undefined here console.log('before return ' + this.userToken);此处未定义console.log('before return ' + this.userToken); because getIdToken() returns a Promise which means it is asynchronous, therefore the only way to access the userToken is inside the then() method.因为getIdToken()返回一个Promise ,这意味着它是异步的,因此访问userToken的唯一方法是在then()方法中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM