[英]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.