如何正确发送令牌?

时间:2019-09-13 16:37:54

标签: angular jwt

我尝试在我的应用中设置身份验证。登录时,我从后端收到令牌。我有一个拦截器,用于向请求标头添加令牌。但是,当我登录时,我重定向然后请求用户列表,但收到错误消息:未提供令牌。当我重新加载页面时,会收到用户列表。我不知道为什么

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

这就像拦截器不会直接拦截用户列表中的请求一样。有什么建议吗?

2 个答案:

答案 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'));
        }

这样,您可以确信在发出任何请求之前已将令牌加载到授权服务中。