gpt4 book ai didi

angular - apollo-angular 中的 token 刷新错误

转载 作者:行者123 更新时间:2023-12-03 17:23:09 25 4
gpt4 key购买 nike

我正在使用 apollo-angular 构建一个前端应用程序。在我的应用程序中,我使用带有短期访问 token 和长期刷新 token 的 JWT 身份验证系统(它们在仅 HTTP 的 cookie 中传输,而不是开始存储在 HTTP header 中)。
当我运行我的应用程序时,我可以成功登录,但是当访问 token 过期时,我收到以下错误并且在我的浏览器上看不到任何内容。Error: Network error: Cannot read property 'refresh' of undefined at new ApolloError我的代码如下:
GraphQL 模块 (在 AppModule 中导入)(部分基于 this question )

import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { ApolloModule, APOLLO_OPTIONS } from 'apollo-angular';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLinkModule, HttpLink } from 'apollo-angular-link-http';
import { ApolloLink, Observable } from 'apollo-link';
import { onError } from 'apollo-link-error';

import { AuthService } from '../account/auth/auth.service';
import { environment } from '../../environments/environment';

const promiseToObservable = (promise: Promise<any>) =>
new Observable((subscriber: any) => {
promise.then(
value => {
if (subscriber.closed) {
return;
}
subscriber.next(value);
subscriber.complete();
},
err => subscriber.error(err)
);
});

const errorLink = onError(({ graphQLErrors, networkError }) => { // need help on linking this with graphql module
if (graphQLErrors) {
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
),
);
}

if (networkError) { console.log(`[Network error]: ${networkError}`); }
});

export function createApollo(httpLink: HttpLink, authService: AuthService) {
const basicLink = httpLink.create({
uri: environment.apiUrl,
withCredentials: true,
});

const authMiddleware = new ApolloLink((operation, forward) => {
if (operation.operationName !== 'RefreshToken') {
if (localStorage.getItem('loginStatus') && localStorage.getItem('loginStatus') === '1') {
const nowtime = new Date();
const accessExpiresIn = new Date(localStorage.getItem('accessExpiresIn'));
const refreshExpiresIn = new Date(localStorage.getItem('refreshExpiresIn'));
if (accessExpiresIn <= nowtime && refreshExpiresIn > nowtime) {
return promiseToObservable(authService.refresh().toPromise()).flatMap(() => forward(operation));
} else if (accessExpiresIn <= nowtime && refreshExpiresIn <= nowtime) {
return promiseToObservable(authService.logout().toPromise()).flatMap(() => forward(operation));
} else {
return forward(operation);
}
} else {
return forward(operation);
}
} else {
return forward(operation);
}
});

const link = ApolloLink.from([errorLink, authMiddleware, basicLink]);
const cache = new InMemoryCache();

return {
link,
cache,
};
}

@NgModule({
imports: [
HttpClientModule,
ApolloModule,
HttpLinkModule
],
exports: [
ApolloModule,
HttpLinkModule
],
providers: [
{
provide: APOLLO_OPTIONS,
useFactory: createApollo,
deps: [HttpLink, AuthService],
},
],
})
export class GraphQLModule { }
认证服务
import { map } from 'rxjs/operators';

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';

import { Apollo } from 'apollo-angular';
import gql from 'graphql-tag';

const login = gql`
mutation Login($username: String!, $password: String!) {
getToken (
email: $username,
password: $password
) {
payload
refreshExpiresIn
}
}
`;

const refresh = gql`
mutation RefreshToken {
refreshToken {
payload
refreshExpiresIn
}
}
`;

const logout = gql`
mutation Logout {
deleteTokenCookie {
deleted
}
deleteRefreshTokenCookie {
deleted
}
}
`;

@Injectable({
providedIn: 'root',
})
export class AuthService {

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

saveExpiresIn(accessExpiresIn: number, refreshExpiresIn: number) {
const accessExpiresIn = new Date(accessExpiresIn * 1000);
const refreshExpiresIn = new Date(refreshExpiresIn * 1000);
localStorage.setItem('accessExpiresIn', accessExpiresIn.toString());
localStorage.setItem('refreshExpiresIn', refreshExpiresIn.toString());
}

login(username: string, password: string) {
return this.apollo.mutate({
mutation: login,
variables: {
username,
password,
},
}).pipe(map((result: any) => {
this.saveExpiresIn(
result.data.tokenAuth.payload.exp,
result.data.tokenAuth.refreshExpiresIn
);
localStorage.setItem('loginStatus', String(1));

return result;
}));
}

refresh() {
return this.apollo.mutate({
mutation: refresh
}).pipe(map((result: any) => {
this.saveExpiresIn(
result.data.refreshToken.payload.exp,
result.data.refreshToken.refreshExpiresIn
);

return result;
}));
}

logout() {
return this.apollo.mutate({
mutation: logout
}).pipe(map((result: any) => {
localStorage.removeItem('loginStatus');
localStorage.removeItem('accessExpiresIn');
localStorage.removeItem('refreshExpiresIn');

return result;
}));
}
}
编写这些代码是为了实现以下应用流程:
  • 用户尝试登录(通过 graphql 突变发送认证信息)
  • 后端服务器将访问 token 和刷新 token 发送到前端应用
  • 用户尝试发送graphql查询,其结果根据用户是否经过身份验证而变化(未经过身份验证的用户也可以看到查询结果)
  • 前端应用检查用户是否登录以及访问 token 是否过期
  • 如果用户已登录并且访问 token 已过期,则前端应用程序会发送带有 graphql 突变的刷新 token 以在原始查询之前获取新的访问 token
  • 新访问 token 发回后发送原始查询

  • 我正在使用 Angular8 和 apollo-angular 1.8.0。
    我对 Angular 很陌生,所以我可能会遗漏一些非常简单的东西;(
    先感谢您!

    最佳答案

    不确定确切的解决方案,但您可以尝试处理 refresh() 中的错误。带有 catchError 的方法RxJS 运算符 - 也许您需要重试,或者您可以查看有关错误的更多详细信息并追溯它。

    import { catchError, map } from 'rxjs/operators';
    import { of } from 'rxjs';

    //...

    @Injectable({
    providedIn: 'root',
    })
    export class AuthService {

    //...

    refresh() {
    return this.apollo.mutate({
    mutation: refresh
    }).pipe(
    map((result: any) => {
    if (result) {
    //...
    }
    else {
    console.warn("There was an error. See output above for details.")
    }
    }),
    catchError((error: Error) => {
    // handle the error, maybe retry
    console.log(error && error.message);
    return of(null);
    })
    );
    }

    //...

    }

    关于angular - apollo-angular 中的 token 刷新错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64987061/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com