如何在角度8中将Firebase jwt getIdToken发送到http get请求?

时间:2019-10-25 10:28:20

标签: javascript angular firebase firebase-authentication

我正在使用角度8制作SPA。

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

后端是由django 2.2和django rest框架组成的API,该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.....'
    }),
  };

但是,当我尝试执行代码中给出的相同操作时,它将无法正常工作。 用户令牌仍未定义。

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

Peter's answer的症结所在:def forAll(x1r): d=6 F = []#K.zeros((K.shape(x1r)[0],K.shape(x1r)[1],d)) for i in range(K.int_shape(x1r)[1]): print('pixel ',i) #in 36 because for each pixel T = countSh(i,d,x1r[:,i,:]) F.append(T) F=tf.stack(F) #non differentiable return F def compact(modelCN,d,interpolSize,noClasse): input = Input(shape=(interpolSize, interpolSize, 3), name='input') x1 = modelCN(input) # output cnn1 ##shape = (?,6,6,512) b=K.int_shape(x1)[1]*K.int_shape(x1)[2] x1r = keras.layers.Reshape([b,K.int_shape(x1)[3]])(x1) F = Lambda(forAll)([x1r]) D = Dense(noClasse, activation='softmax',name='dense1')(F) extractor2 = Model(inputs=input, outputs=D) return extractor2 ######### MAIN if "sess" in locals(): # this code prevent creating many intance of tf.compat.v1.reset_default_graph() sess.close() # tensorflow in memory (that can cause crashes) K.clear_session() sess = tf.InteractiveSession() model = Sequential() model.add(Conv2D(filters=128, kernel_size=3, strides=1, input_shape=(64,64,1),activation='relu')) model.add(MaxPooling2D(pool_size=(2,2), strides=2)) model.add(Conv2D(filters=256, kernel_size=3, strides=1, activation='relu')) model.add(MaxPooling2D(pool_size=(2,2), strides=2)) model.add(Conv2D(filters=512, kernel_size=3,strides=1,activation='relu')) model.add(MaxPooling2D(pool_size=(2,2), strides=2)) extract = compact(model,6,64,47) extract.compile(optimizer=adam(lr=0.01,decay=0.00001), loss='categorical_crossentropy', metrics=['accuracy']) 是异步的,因此,在您的getIdToken()运行时,return this.userToken;尚未运行。您应该能够从this.userToken = idToken;语句的输出中看到这一点。

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

代码的解决方法是返回console.log,而不是尝试返回值:

Promise

换句话说:GetToken(): string { return new Promise((resolve, reject) => { this.afAuth.auth.onAuthStateChanged( user => { if (user) { user.getIdToken().then(idToken => { this.userToken = idToken; resolve(idToken); }); } }); }) } 返回一个承诺,该承诺将在ID令牌可用时解决。如果您知道调用此函数时用户已经登录,则可以将其简化为:

GetToken

区别在于第二个功能不等待用户登录,因此如果没有登录用户,该功能将失败。

然后您可以在GetToken(): string { const user = firebase.authentication().currentUser; return user.getIdToken() } 中使用以上任一功能:

getEmployees