使用 graphql 和 apollo 客户端刷新 angular 的令牌循环依赖问题

时间:2021-03-10 12:15:26

标签: angular typescript graphql apollo refresh-token

当我的请求返回 401 时,我正在尝试设置刷新令牌策略以使用 GraphQL 和 apollo 客户端以 Angular 刷新 JWT。错误检测有效,但我无法进行服务注入。 Angular 在控制台中返回一个关于循环依赖检测的错误

<块引用>

ERROR 错误:NG0200:检测到 DI 中的循环依赖 身份验证服务

我不知道如何解决它。 有错误画面 Screen of the error

这是我的 graphql.module.ts:

import { NgModule } from '@angular/core';
import { APOLLO_OPTIONS } from 'apollo-angular';
import { ApolloLink, InMemoryCache } from '@apollo/client/core';
import { HttpLink } from 'apollo-angular/http';
import { environment } from 'src/environments/environment';
import { setContext } from '@apollo/client/link/context';
import { onError } from "@apollo/client/link/error";
import { AuthService } from './services/auth/auth.service';

const uri = environment.apiUrl + 'graphql'; // <-- add the URL of the GraphQL server here

export function createApollo(httpLink: HttpLink, authService: AuthService) {

  const basic = setContext((operation, context) => ({
    headers: {
      Accept: 'charset=utf-8'
    }
  }));

  const error = onError(({ graphQLErrors, networkError, response, operation }) => {
    if (graphQLErrors[0].extensions.exception.status == 401) {
      authService.refreshToken().subscribe(res => {
        console.log(res)
      })
    }
  })

  const auth = setContext((operation, context) => {
    const token = localStorage.getItem('JWT_TOKEN');

    if (token === null) {
      return {};
    } else {
      return {
        headers: {
          Authorization: `Bearer ${token}`
        }
      };
    }
  });

  const link = ApolloLink.from([basic, error, auth, httpLink.create({ uri })]);
  const cache = new InMemoryCache();

  return {
    link,
    cache
  }
}

@NgModule({
  providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory: createApollo,
      deps: [HttpLink, AuthService],
    },
  ],
})
export class GraphQLModule { }

这是我的 auth.service.ts

import { Injectable } from '@angular/core';
import { Apollo } from 'apollo-angular';
import { LoginResponse, LOGIN_MUTATION, MeQueryResponse, ME_QUERY, RefreshTokenResponse, REFRESH_TOKEN_MUTATION, User } from 'src/app/models/graphql';
import { tap } from 'rxjs/operators';
import { Tokens } from 'src/app/models/tokens';
import { Storage } from '@ionic/storage';
import { Router } from '@angular/router';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private readonly JWT_TOKEN = 'JWT_TOKEN';
  private readonly REFRESH_TOKEN = 'REFRESH_TOKEN';
  private loggedUser: string;
  USER = new BehaviorSubject<User>(null);
  isAdmin!: boolean;

  constructor(private apollo: Apollo, private router: Router, private storage: Storage) { }

  login(email: string, password: string) {
    return this.apollo.mutate<LoginResponse>({
      mutation: LOGIN_MUTATION,
      variables: {
        email,
        password
      }
    })
      .pipe(
        tap(tokens => this.doLoginUser(email, tokens.data.login)),
      );
  }


  getMe() {
    return this.apollo.query<MeQueryResponse>({
      query: ME_QUERY
    })
      .pipe(
        tap(user => this.doSaveUser(user.data.me))
      )
  }

  isLoggedIn() {
    return !!this.getJwtToken();
  }

  refreshToken() {
    return this.apollo.mutate<RefreshTokenResponse>({
      mutation: REFRESH_TOKEN_MUTATION
    })
      .pipe
      (
        tap(tokens => this.storeJwtToken(tokens.data.returnToken.token))
      )
  }

  getJwtToken() {
    return localStorage.getItem(this.JWT_TOKEN);
  }

  getRefreshToken() {
    return localStorage.getItem(this.REFRESH_TOKEN);
  }

  logoutUser() {
    this.loggedUser = null;
    this.router.navigate(["/auth/login"])
    this.removeTokens();
  }

  /* doLoadUser() {
    this.storage.get('USER').then(res => {
      if (res) {
        this.USER.next(res);
        this.isAdmin = res.isAdmin;
      }
    })
  } */

  user() {
    return this.USER;
  }

  private doSaveUser(user: User) {
    this.USER.next(user);
    this.isAdmin = user.isAdmin;
    this.storage.set('USER', user);
  }

  private doLoginUser(email: string, tokens: Tokens) {
    this.loggedUser = email;
    this.storeTokens(tokens);
  }

  private storeJwtToken(jwt: string) {
    localStorage.setItem(this.JWT_TOKEN, jwt);
  }

  private storeTokens(tokens: Tokens) {
    localStorage.setItem(this.JWT_TOKEN, tokens.token);
    localStorage.setItem(this.REFRESH_TOKEN, tokens.refreshToken);
  }

  private removeTokens() {
    localStorage.removeItem(this.JWT_TOKEN);
    localStorage.removeItem(this.REFRESH_TOKEN);
  }
}

有什么想法吗? 任何帮助将不胜感激

0 个答案:

没有答案