Angular 导航YURL似乎';不';不可能发生';在Safari上,如果拦截器在以前的请求中失败
我有一个项目,其中设置了一个拦截器来刷新JWT令牌,如果http请求在其过期后发出,并且用户选择保持登录(与令牌本身一样存储在本地存储中) 此刷新过程的一部分包括一项检查,如果刷新失败或用户未选择保持登录,则该检查可以更改用户的登录状态(通过电子用户服务中的状态跟踪主题) Im在主应用程序组件中订阅了此状态更改,当它检测到用户已注销时,将(通过router.navigateByUrl)将用户导航到登录页面 这在除safari之外的所有浏览器上都能正常工作。我真的很难弄明白它为什么会失败。起初,我认为可能是因为我没有正确处理刷新异常而导致失败,但在显式捕获该错误之后,一个控制台日志语句演示了“navigateByUrl”调用实际上正在运行(通过将console.log语句放入调用的.then回调中)我完全搞不懂为什么浏览器没有更新Angular 导航YURL似乎';不';不可能发生';在Safari上,如果拦截器在以前的请求中失败,angular,safari,jwt,interceptor,Angular,Safari,Jwt,Interceptor,我有一个项目,其中设置了一个拦截器来刷新JWT令牌,如果http请求在其过期后发出,并且用户选择保持登录(与令牌本身一样存储在本地存储中) 此刷新过程的一部分包括一项检查,如果刷新失败或用户未选择保持登录,则该检查可以更改用户的登录状态(通过电子用户服务中的状态跟踪主题) Im在主应用程序组件中订阅了此状态更改,当它检测到用户已注销时,将(通过router.navigateByUrl)将用户导航到登录页面 这在除safari之外的所有浏览器上都能正常工作。我真的很难弄明白它为什么会失败。起初,我
// app.component catching the sign out to redirect user, note the 'Nav to the home page worked'
this.userService.getSignInStateSubject().subscribe(state => {
// if we were signed in and now we are not, redirect user immediately
console.log('why has this not changed', state, this.signedInState);
if (!state && this.signedInState) {
// adding cleanup for log out here, rather than scatter it all over the place
this.productService.setCurrentSelectedProduct(undefined);
console.log('this needs to change immediately');
this.routerService.navigateByUrl('/login').then(success => {
console.log('Nav to the home page worked');
}, error => {
console.log(error);
});
}
this.signedInState = state;
});
\\用户服务“刷新”方法
公共attemptTokenRefresh():承诺{
返回新承诺((解决、拒绝)=>{
//console.log('我们在这里进行刷新'、localStorage.getItem(这个.STAY\u-SIGNED\u-IN\u-KEY)、Boolean(数字(localStorage.getItem(这个.STAY\u-SIGNED\u-IN\u-KEY))、localStorage.getItem(这个.refresh\u-TOKEN\u-KEY));
//如果用户选择不保持登录,则拒绝
if(!Boolean(数字(localStorage.getItem(this.STAY\u SIGNED\u IN\u KEY))){
这个.clearStoredData();
this.userSubject.next(未定义);
拒绝(“由于用户选择不保持登录,刷新失败”);
返回;
}
const refreshToken=localStorage.getItem(此.REFRESH\u令牌\u密钥);
//如果缺少或无效的刷新令牌,则拒绝
如果(!刷新令牌){
这个.clearStoredData();
this.userSubject.next(未定义);
拒绝('刷新失败,因为刷新令牌无效');
返回;
}
//尝试刷新
this.httpClient.post(environment.api_url+'/'+environment.refresh_令牌,JSON.stringify({refreshttoken}){
标题:新的HttpHeaders({
“内容类型”:“应用程序/json”
})
}).subscribe((authResult:{accessToken:string,refreshToken:string})=>{
//更新存储的令牌
setItem(this.ACCESS\u TOKEN\u密钥authResult.accessToken);
setItem(this.REFRESH\u TOKEN\u KEY,authResult.refreshToken);
const newTokenObject=this.parseAccessToken(authResult.accessToken);
//使用更新的令牌解析,以便在init函数或auth拦截器中使用
解析(authResult.accessToken);
},错误=>{
这个.clearStoredData();
this.userSubject.next(未定义);
拒绝(错误);
});
});
}
有人知道为什么这不起作用吗?(特别是在Safari vs chrome上,它似乎可以按预期工作时,不应该工作)
// auth interceptor
return next.handle(authReq).pipe(catchError(err => {
// we need to make sure we dont try to refresh on authentication failure
if ([400, 401].indexOf(err.status) > -1 && req.url !== environment.api_url + '/' + environment.tokens) {
userService.redirectUrl = routingService.url;
// convert to an observable and pipe the result
return from(userService.attemptTokenRefresh()).pipe(
catchError(error => {
console.log('this caught the error and did nothing with it');
return of(error);
}),
switchMap(result => {
console.log('result', result);
if (result instanceof String) {
console.log('this got a real result');
authReq = req.clone({
setHeaders: { Authorization: 'Bearer ' + result }
});
return next.handle(authReq);
} else {
console.log('this has not worked well at all', result);
return EMPTY;
}
}),
);
} else {
return throwError(err);
}
}));
\\ user service 'refresh' method
public attemptTokenRefresh(): Promise<string> {
return new Promise((resolve, reject) => {
// console.log('here we are doing the refresh', localStorage.getItem(this.STAY_SIGNED_IN_KEY), Boolean(Number(localStorage.getItem(this.STAY_SIGNED_IN_KEY))), localStorage.getItem(this.REFRESH_TOKEN_KEY));
// reject if user chose not to stay signed in
if (!Boolean(Number(localStorage.getItem(this.STAY_SIGNED_IN_KEY)))) {
this.clearStoredData();
this.userSubject.next(undefined);
reject('Refresh failed as user chose not to stay signed in');
return;
}
const refreshToken = localStorage.getItem(this.REFRESH_TOKEN_KEY);
// reject if we have a missing or invalid refresh token
if (!refreshToken) {
this.clearStoredData();
this.userSubject.next(undefined);
reject('Refresh failed because of invalid refresh token');
return;
}
// attempt a refresh
this.httpClient.post(environment.api_url + '/' + environment.refresh_tokens, JSON.stringify({ refreshToken }), {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
}).subscribe((authResult: { accessToken: string, refreshToken: string }) => {
// update the stored tokens
localStorage.setItem(this.ACCESS_TOKEN_KEY, authResult.accessToken);
localStorage.setItem(this.REFRESH_TOKEN_KEY, authResult.refreshToken);
const newTokenObject = this.parseAccessToken(authResult.accessToken);
// resolve with the updated token for use ether in the init function or auth interceptor
resolve(authResult.accessToken);
}, error => {
this.clearStoredData();
this.userSubject.next(undefined);
reject(error);
});
});
}