处理刷新使用rxjs令牌 [英] Handling refresh tokens using rxjs

查看:170
本文介绍了处理刷新使用rxjs令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因为我已经开始与angular2我有我设置的服务来回报观测T.在服务我将不得不在地图()调用,并使用这些服务只是将使用订阅组件()来等待响应。对于这些简单的场景我没有真正需要掏rxjs所以一切都ok了。

Since i've started with angular2 i have setup my services to return Observable of T. In the service i would have the map() call, and components using these services would just use subscribe() to wait for the response. For these simple scenarios i didnt really need to dig in to rxjs so all was ok.

我现在要实现以下目标:我使用与刷新令牌的OAuth2验证。我想建立所有其他服务将使用一个API服务,这将透明地处理刷新令牌则返回401错误时。所以,在401的情况下,我第一次提取从端点的OAuth2一个新的令牌,然后重试我的新的令牌请求。下面是code,它做工精细,用承诺:

I now want to achieve the following: i am using Oauth2 authentication with refresh tokens. I want to build an api service that all other services will use, and that will transparently handle the refresh token when a 401 error is returned. So, in the case of a 401, i first fetch a new token from the OAuth2 endpoint, and then retry my request with the new token. Below is the code that works fine, with promises:

request(url: string, request: RequestOptionsArgs): Promise<Response> {
    var me = this;

    request.headers = request.headers || new Headers();
    var isSecureCall: boolean =  true; //url.toLowerCase().startsWith('https://');
    if (isSecureCall === true) {
        me.authService.setAuthorizationHeader(request.headers);
    }
    request.headers.append('Content-Type', 'application/json');
    request.headers.append('Accept', 'application/json');

    return this.http.request(url, request).toPromise()
        .catch(initialError => {
            if (initialError && initialError.status === 401 && isSecureCall === true) {
                // token might be expired, try to refresh token. 
                return me.authService.refreshAuthentication().then((authenticationResult:AuthenticationResult) => {
                    if (authenticationResult.IsAuthenticated == true) {
                        // retry with new token
                        me.authService.setAuthorizationHeader(request.headers);
                        return this.http.request(url, request).toPromise();
                    }
                    return <any>Promise.reject(initialError);
                });
            }
            else {
                return <any>Promise.reject(initialError);
            }
        });
}

在code以上,authService.refreshAuthentication()将获取新的令牌并将其存储在localStorage的。 authService.setAuthorizationHeader将设置'授权'头previously更新令牌。如果你看一下抓方法,你会看到它返回一个承诺(用于刷新令牌),在其回合最终会返回另一个承诺(实际试第二次请求)。

In the code above, authService.refreshAuthentication() will fetch the new token and store it in localStorage. authService.setAuthorizationHeader will set the 'Authorization' header to previously updated token. If you look at the catch method, you'll see that it returns a promise (for the refresh token) that in its turns will eventually return another promise (for the actual 2nd try of the request).

我试图做到这一点,而不诉诸承诺:

I have attempted to do this without resorting to promises:

request(url: string, request: RequestOptionsArgs): Observable<Response> {
    var me = this;

    request.headers = request.headers || new Headers();
    var isSecureCall: boolean =  true; //url.toLowerCase().startsWith('https://');
    if (isSecureCall === true) {
        me.authService.setAuthorizationHeader(request.headers);
    }
    request.headers.append('Content-Type', 'application/json');
    request.headers.append('Accept', 'application/json');

    return this.http.request(url, request)
        .catch(initialError => {
            if (initialError && initialError.status === 401 && isSecureCall === true) {
                // token might be expired, try to refresh token
                return me.authService.refreshAuthenticationObservable().map((authenticationResult:AuthenticationResult) => {
                    if (authenticationResult.IsAuthenticated == true) {
                        // retry with new token
                        me.authService.setAuthorizationHeader(request.headers);
                        return this.http.request(url, request);
                    }
                    return Observable.throw(initialError);
                });
            }
            else {
                return Observable.throw(initialError);
            }
        });
}

在code上面没有做什么,我希望:在200响应的情况下,适当地返回响应。然而,如果捕获401,它会成功地检索新令牌,但订阅港岛线最终检索可观察到的,而不是响应。即时猜测这是未执行的可观察到的是应该做的重试。

The code above does not do what i expect: in the case of a 200 response, it properly returns the response. However, if it catches the 401, it will successfully retrieve the new token, but the subscribe wil eventually retrieve an observable instead of the response. Im guessing this is the unexecuted Observable that should do the retry.

我意识到,翻译工作到rxjs库的承诺的方式可能不是最好的一段路要走,但我还没有能够把握一切都是一个流的事情。我曾尝试涉及flatmap,retryWhen等一些其他的解决方案...但没有得到远,所以一些帮助AP preciated。

I realize that translating the promise way of working onto the rxjs library is probably not the best way to go, but i havent been able to grasp the "everything is a stream" thing. I have tried a few other solutions involving flatmap, retryWhen etc ... but didnt get far, so some help is appreciated.

推荐答案

从快看看你的code,我会说,你的问题似乎是,你是不是压扁观测即从刷新服务返回。

From a quick look at your code I would say that your problem seems to be that you are not flattening the Observable that is returned from the refresh service.

运营商期望,你会返回一个观测这将连接到失败的观测年底使下游观察不知道其中的差别。

The catch operator expects that you will return an Observable that it will concatenate onto the end of the failed Observable so that the down stream Observer doesn't know the difference.

在非401情况下,你是否正确通过返回一个观测该重新抛出初始误差这样做。然而,在刷新情况下,你正在返回一个观测中产生的的更多观测量而不是单值。

In the non-401 case you are doing this correctly by returning an Observable that rethrows the initial error. However in the refresh case you are returning an Observable the produces more Observables instead of single values.

我建议你更改刷新逻辑是:

I would suggest you change the refresh logic to be:

    return me.authService
             .refreshAuthenticationObservable()
             //Use flatMap instead of map
             .flatMap((authenticationResult:AuthenticationResult) => {
                   if (authenticationResult.IsAuthenticated == true) {
                     // retry with new token
                     me.authService.setAuthorizationHeader(request.headers);
                     return this.http.request(url, request);
                   }
                   return Observable.throw(initialError);
    });

flatMap 将中间观测量转换成一个单一的数据流。

flatMap will convert the intermediate Observables into a single stream.

这篇关于处理刷新使用rxjs令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆