我尝试在我的应用中设置身份验证。登录时,我从后端收到令牌。我有一个拦截器,用于向请求标头添加令牌。但是,当我登录时,我重定向然后请求用户列表,但收到错误消息:未提供令牌。当我重新加载页面时,会收到用户列表。我不知道为什么
auth.service
export class AuthenticationService {
private currentUserSubject: BehaviorSubject<User>;
public currentUser: Observable<User>;
public currentToken: BehaviorSubject<string>;
constructor(private http: HttpClient) {
this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('currentUser')));
this.currentUser = this.currentUserSubject.asObservable();
this.currentToken = new BehaviorSubject<string>(localStorage.getItem('currentToken'));
}
public get currentTokenValue() {
return this.currentToken.value;
}
public get currentUserValue(): User {
return this.currentUserSubject.value;
}
login(loguser: User) {
return this.http.post<any>(`${environment.apiUrl}/authenticate`,
loguser , { headers: new HttpHeaders().set('Content-Type', 'application/json')})
.pipe(map(user => {
// store user details and jwt token in local storage to keep user logged in between p
//console.log('voilavoila :'+user.user[0]);
//user.token = user.token;
localStorage.setItem('currentUser', JSON.stringify(user.user[0]));
localStorage.setItem('currentToken',user.token);
this.currentUserSubject.next(user);
console.log('localsss'+localStorage.getItem('currentToken'), ' ', localStorage.getIte
// console.log('testuserrole : '+JSON.parse(localStorage.getItem('currentUser'))
return user;
}));
}
logout() {
// remove user from local storage to log user out
localStorage.removeItem('currentUser');
localStorage.removeItem('currentToken');
this.currentUserSubject.next(null);
}
}
拦截器
export class JwtInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthenticationService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// add authorization header with jwt token if available
let currentUser = this.authenticationService.currentUserValue;
let currentToken = this.authenticationService.currentTokenValue;
if (currentUser && currentToken) {
console.log(currentToken);
request = request.clone({
setHeaders: {
Authorization: `Bearer ${currentToken}`
}
});
}
return next.handle(request);
}
}
在我的身份验证请求的回调中,我只是导航到主页
home.component
export class HomeComponent {
loading = false;
users: User[];
constructor(private userService: UserService) { }
ngOnInit() {
this.loading = true;
this.userService.getAll().pipe(first()).subscribe(users => {
console.log('récupération des users');
this.loading = false;
this.users = users;
});
}
}
这就像拦截器不会直接拦截用户列表中的请求一样。有什么建议吗?
答案 0 :(得分:1)
您的代码完全按照应有的方式工作...那会发生什么?
应用程序在用户未登录时启动:
this.currentToken = new BehaviorSubject<string>(localStorage.getItem('currentToken'));
好的,由于没有用户,因此我们在currentToken
中没有值。因此,接下来,您登录并执行以下操作:
localStorage.setItem('currentToken',user.token);
用户将被重定向到您重定向用户的任何页面,并在该页面上触发需要令牌的http请求,但是拦截器会得到什么?因为没有在behaviorsubject上调用currentToken.value
,所以它得到的next
没有值,因此原始的undefined
值仍然存在。
无论如何,无论如何我都不会对行为主体打电话value
,我认为这有点违背不可观测的目的。
总而言之,您应该在拦截器本身中处理令牌的获取,或者在登录后在behaviorsubject上调用next
。我会做第一个选择。
答案 1 :(得分:1)
考虑到刷新时会收到用户列表,我猜测您的AuthenticationService
到您的App首次请求用户列表时尚未加载。因此,在这种情况下,我建议您解决此问题。
更改app.module.ts
以在初始化时加载授权服务,如下所示:
declarations: [
.
.
.
],
imports: [
.
.
.
],
providers: [
AuthenticationService,
{
provide: APP_INITIALIZER,
useFactory: (as: AuthService) =>
function() {
return as.load();
},
deps: [AuthenticationService],
multi: true
},
.
.
.
],
bootstrap: [AppComponent]
})
然后,您需要更改授权服务,以在将要创建的load
方法中加载令牌。像这样
export class AuthenticationService {
private currentUserSubject: BehaviorSubject<User>;
public currentUser: Observable<User>;
public currentToken: BehaviorSubject<string>;
constructor(private http: HttpClient) {
//move everythign that was here to the load function
}
load(){
this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('currentUser')));
this.currentUser = this.currentUserSubject.asObservable();
this.currentToken = new BehaviorSubject<string>(localStorage.getItem('currentToken'));
}
这样,您可以确信在发出任何请求之前已将令牌加载到授权服务中。