当前位置: 首页 > 面试题库 >

AngularJS-HTTP拦截器-令牌刷新后重新发送所有请求

赫连晋
2023-03-14
问题内容

我有一个有角度的应用程序,有时每个状态会执行多个$
http.get请求。该应用将JWT用于带有刷新令牌的用户身份验证。API服务器会发送401由于身份验证错误而失败的每个请求。我做了一个http interceptor请求,该请求在401错误时请求带有刷新令牌的新令牌,然后重新发送原始请求。

问题是,如果一个状态发出例如2个$
http.get请求,并且都获得401响应,那么我将访问令牌更新两次。显然,我只想刷新一次令牌,但是我仍然想重新发送两个失败的请求。

这是可以实现的吗?

app.factory('AuthInterceptor', function($q, $injector, RESOURCE_URL, API_BASE, authService) {
    return {
        request: function(config) {
            config.headers = config.headers || {};
            if (authService.getAccessToken()) {
                if (config.url.substring(0, RESOURCE_URL.length) !== RESOURCE_URL) {
                    config.headers.Authorization = 'Bearer ' + authService.getAccessToken();
                }
            }
            return config;
        },
        responseError: function(response) {
            switch (response.status) {
                case 401:
                    var deferred = $q.defer();
                    $injector.get("$http").post(API_BASE + '/api/auth/refresh', {refreshtoken: authService.getRefreshToken()}).then(function(r) {
                        if (r.data.data.accesstoken && r.data.data.refreshtoken && r.data.data.expiresin) {
                            authService.setAccessToken(r.data.data.accesstoken);
                            authService.setRefreshToken(r.data.data.refreshtoken);
                            authService.setExpiresIn(r.data.data.expiresin);
                            $injector.get("$http")(response.config).then(function(resp) {
                                deferred.resolve(resp);
                            },function(resp) {
                                deferred.reject();
                            });
                        } else {
                            deferred.reject();
                        }
                    }, function(response) {
                        deferred.reject();
                        authService.clear();
                        $injector.get("$state").go('guest.login');
                        return;
                    });
                    return deferred.promise;
                    break;
                default:
                    authService.clear();
                    $injector.get("$state").go('guest.login');
                    break;
            }
            return response || $q.when(response);
        }
    };
});

问题答案:

您的拦截器需要跟踪其是否有“运行中”的身份验证请求。它可以通过保留对身份验证请求返回的承诺的引用来实现。如果有一个正在处理中的请求,而您又收到另一个401,则只需使用该缓存的Promise即可,而不是发起新的请求。另外,您应该考虑添加逻辑以解决’/
api / auth / refresh’本身返回401的情况。

app.factory('AuthInterceptor', function($q, $injector, RESOURCE_URL, API_BASE, authService) {
    var inflightAuthRequest = null;
    return {
        request: function(config) {
            config.headers = config.headers || {};
            if (authService.getAccessToken()) {
                if (config.url.substring(0, RESOURCE_URL.length) !== RESOURCE_URL) {
                    config.headers.Authorization = 'Bearer ' + authService.getAccessToken();
                }
            }
            return config;
        },
        responseError: function(response) {
            switch (response.status) {
                case 401:
                    var deferred = $q.defer();
                    if(!inflightAuthRequest) {
                        inflightAuthRequest = $injector.get("$http").post(API_BASE + '/api/auth/refresh', {refreshtoken: authService.getRefreshToken()});
                    }
                    inflightAuthRequest.then(function(r) {
                        inflightAuthRequest = null;
                        if (r.data.data.accesstoken && r.data.data.refreshtoken && r.data.data.expiresin) {
                            authService.setAccessToken(r.data.data.accesstoken);
                            authService.setRefreshToken(r.data.data.refreshtoken);
                            authService.setExpiresIn(r.data.data.expiresin);
                            $injector.get("$http")(response.config).then(function(resp) {
                                deferred.resolve(resp);
                            },function(resp) {
                                deferred.reject();
                            });
                        } else {
                            deferred.reject();
                        }
                    }, function(response) {
                        inflightAuthRequest = null;
                        deferred.reject();
                        authService.clear();
                        $injector.get("$state").go('guest.login');
                        return;
                    });
                    return deferred.promise;
                    break;
                default:
                    authService.clear();
                    $injector.get("$state").go('guest.login');
                    break;
            }
            return response || $q.when(response);
        }
    };
});


 类似资料:
  • 我有 401 拦截器,当access_token过期时,有一个请求的成功案例。拦截器重新加载令牌并返回 next.handle(customReq)。但是当同时发出 2 个或更多请求并且两个请求的令牌都已过期时,我遇到了问题,因为第二个请求尝试再次刷新,但现在刷新令牌无效。所以。。。。我尝试设置一个标志只执行一次,并使用自定义可观察量返回。问题是组件现在永远不会成功,我无法删除加载器。 HTTP

  • 我需要(在拦截器类中)对403禁止的HTTP状态(获取/刷新)JWT令牌作出反应,并使用新令牌重试请求。 在下面的代码中,当服务器返回错误响应时,它将转到成功回调(而不是像我预期的那样进入错误回调),事件是typeof object(这在错误响应的反应中是无用的)。事件对象如下所示:{type:0}。 问题: -当我需要刷新accessToken并重试http请求时,如何在HttpIntercep

  • 问题内容: 我似乎无法让$ httpProvider.interceptors实际进行拦截。我在JSFiddle上创建了一个示例,该示例记录了拦截器运行的时间以及$ http响应成功的时间。在成功返回响应之后,将运行请求拦截器。这似乎有些倒退。 我不能使用transformRequest,因为我需要更改配置中的参数。该部分未显示在示例中。 我正在使用AngularJS 1.1.5 http://j

  • 我有一个使用express api的react应用程序。我正在尝试在访问令牌过期时刷新令牌。我正在使用axios拦截器来实现这一成就。 它卡在某个地方了。我使用console.log来调试它。从控制台; 发布http://localhost:5000/api/auth/token?null 401(未经授权) 之后什么都没发生。我该怎么办?谢谢你的帮助

  • 问题内容: 我目前在一个有角度的应用程序中工作,我想为我的应用程序中的所有http请求编写一个拦截器,这反过来会调用一个服务,以了解单点登录会话是否仍处于活动状态,如果未处于活动状态,我应该转到我的单点登录,然后根据用户请求加载下一页或结果。我不确定如何在AngularJS中编写拦截器,也不确定将页面重定向到“单一登录”时如何保存用户请求。 我当前正在使用angularjs 1.0.2,我看到在1

  • 您好,我正试图通过刷新令牌并重试请求,找出如何实现新的角度拦截器和处理错误。这是我一直遵循的指南:https://ryanchenkie.com/angular-authentication-using-the-http-client-and-http-interceptors 我成功缓存失败的请求,并可以刷新令牌,但我不知道如何重新发送以前失败的请求。我还想让它与我目前使用的解析器一起工作。 t