【问题标题】:How to send firebase jwt getIdToken to http get request in angular 8?如何将firebase jwt getIdToken发送到角度8的http get请求?
【发布时间】:2019-10-25 10:28:20
【问题描述】:

我正在使用 Angular 8 制作 SPA。

Firebase 用于在客户端和后端对用户进行身份验证,因此我需要将 http.get 请求中的 jwt 令牌发送到后端以对用户进行身份验证。

Backend 是使用 django 2.2 和 django rest 框架制作的 API,用于发送要在客户端应用程序中使用的 API。

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

@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);
  }

}

后端工作正常,我通过在 httpOptions 中添加令牌进行了验证,如下所示:

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

但是当我尝试按照代码中给出的相同操作时,它不起作用。 用户令牌仍未定义。

【问题讨论】:

    标签: javascript angular firebase firebase-authentication


    【解决方案1】:

    Peter's answer 的关键在于:getIdToken() 是异步的,所以当你的return this.userToken; 运行时,this.userToken = idToken; 还没有运行。您应该能够从 console.log 语句的输出中看到这一点。

    有关此问题的更多信息,请参阅 How to return value from an asynchronous callback function? 我强烈建议研究这个答案一段时间,因为这种异步行为在处理 Web API 时非常普遍。

    您的代码的修复方法是返回 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);    
            });
          }
        });
      })
    }
    

    换句话说:GetToken 返回一个承诺,一旦 ID 令牌可用,该承诺就会解决。如果您在调用此函数时知道用户已经登录,则可以将其简化为:

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

    不同的是,第二个函数不等待用户登录,所以如果没有登录用户就会失败。

    然后您可以在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);
    
        })
      })
    }
    

    【讨论】:

    • 我需要从 getEmployee() 方法返回 Employee[] 类型的 Observable 但现在它返回了一个承诺。
    • 我的回答侧重于为什么您的 http 选项不能正常工作,并说明了如何解决这个问题。它返回一个解析为Employee[] 的承诺。它也可能返回一个 observable,如以下结果所示:google.com/search?q=turn+promise+into+observable
    • 感谢您提供的链接,我现在明白了如何承诺。至于 promise 到 observable 的转换,我是在 rxjs 中使用 'from' 完成的。我现在正在使用 http 拦截器向所有 http 请求添加令牌。
    【解决方案2】:

    这里没有定义console.log('before return ' + this.userToken);,因为getIdToken()返回一个Promise,这意味着它是异步的,因此访问userToken的唯一方法是在then()方法内部。

    【讨论】:

      猜你喜欢
      • 2016-11-08
      • 2018-02-04
      • 1970-01-01
      • 2016-11-01
      • 1970-01-01
      • 2012-08-30
      • 1970-01-01
      • 2020-03-28
      • 2023-03-18
      相关资源
      最近更新 更多