2017-02-06 9 views
1

私は間違っているかどうかわからないので、これが可能かどうかを知りたいです。基本的には、ネイティブfetch javascript関数のラップ関数を作成することです。このラップ関数はトークンの検証プロセスを実装し、指定されたトークンが期限切れになった場合に新しいaccessTokenを要求し、再度要求するリソースを要求します。これは私が今までに達してきたものである:カスタム機能を追加するためにjavascriptをフェッチする

customFetch.js

// 'url' and 'options' parameters are used strictely as you would use them in fetch. 'authOptions' are used to configure the call to refresh the access token 
window.customFetch = (url, options, authOptions) => { 

    const OPTIONS = { 
     url: '', 
     unauthorizedRedirect: '', 
     storage: window.sessionStorage, 
     tokenName: 'accessToken' 
    } 

    // Merge options passed by user with the default auth options 
    let opts = Object.assign({}, OPTIONS, authOptions); 

    // Try to update 'authorizarion's header in order to send always the proper one to the server 
    options.headers = options.headers || {}; 
    options.headers['Authorization'] = `Bearer ${opts.storage.getItem(opts.tokenName)}`; 

    // Actual server request that user wants to do. 
    const request = window.fetch(url, options) 
     .then((d) => { 
      if (d.status === 401) { 
       // Unauthorized 
       console.log('not authorized'); 
       return refreshAccesToken(); 
      } 
      else { 
       return d.json(); 
      } 
     }); 

    // Auxiliar server call to get refresh the access token if it is expired. Here also check if the 
    // cookie has expired and if it has expired, then we should redirect to other page to login again in 
    // the application. 
    const refreshAccesToken =() => { 
     window.fetch(opts.url, { 
      method: 'get', 
      credentials: 'include' 
     }).then((d) => { 
      // For this example, we can omit this, we can suppose we always receive the access token 
      if (d.status === 401) { 
       // Unauthorized and the cookie used to validate and refresh the access token has expired. So we want to login in to the app again 
       window.location.href = opts.unauthorizedRedirect; 
      } 

      return d.json(); 
     }).then((json) => { 
      const jwt = json.token; 
      if (jwt) { 
       // Store in the browser's storage (sessionStorage by default) the refreshed token, in order to use it on every request 
       opts.storage.setItem(opts.tokenName, jwt); 
       console.log('new acces token: ' + jwt); 

       // Re-send the original request when we have received the refreshed access token. 
       return window.customFetch(url, options, authOptions); 
      } 
      else { 
       console.log('no token has been sent'); 
       return null; 
      } 
     }); 
    } 

    return request; 
} 

consumer.js

const getResourcePrivate =() => { 
     const url = MAIN_URL + '/resource'; 
     customFetch(url, { 
      method: 'get' 
     },{ 
      url: AUTH_SERVER_TOKEN, 
      unauthorizedRedirect: AUTH_URI, 
      tokenName: TOKEN_NAME 
     }).then((json) => { 
      const resource = json ? json.resource : null; 
      if (resource) { 
       console.log(resource); 
      } 
      else { 
       console.log('No resource has been provided.'); 
      } 
     }); 
} 

私は少し良く、上記のコードを説明してみましょう:私は、ユーザーのために透明にします彼らが望むリソースを要求することを心配するために、トークンの検証を行います。 return request命令は、fetch要求の約束を消費者に与えているので、このアプローチはaccessTokenが依然として有効であるときにうまく動作しています。

もちろん、accessTokenが期限切れになり、新しいサーバをauthサーバにリクエストすると、これは動作しません。トークンがリフレッシュされ、プライベートリソースが要求されますが、consumer.jsにはトークンが表示されません。

この最後のシナリオでは、accessTokenをリフレッシュしてプライベートリソースを再度取得するためにサーバーコールを実行するために、プログラムのフローを変更できますか?消費者はこのプロセスについて理解すべきではありません。両方とも(accessTokenが有効で、accessTokenが期限切れになり、更新されている)、consumer.jsは、then機能でプライベートに要求されたリソースを取得する必要があります。

答えて

1

最後に、私は解決策に達しました。私はPromiseを使って解決しようとしました。

window.customFetch = (url, options, authOptions) => { 

    const OPTIONS = { 
     url: '', 
     unauthorizedRedirect: '', 
     storage: window.sessionStorage, 
     tokenName: 'accessToken' 
    } 

    // Merge options passed by user with the default auth options 
    let opts = Object.assign({}, OPTIONS, authOptions); 

    const requestResource = (resolve) => { 
     // Try to update 'authorizarion's header in order to send always the proper one to the server 
     options.headers = options.headers || {}; 
     options.headers['Authorization'] = `Bearer ${opts.storage.getItem(opts.tokenName)}`; 

     window.fetch(url, options) 
      .then((d) => { 
       if (d.status === 401) { 
        // Unauthorized 
        console.log('not authorized'); 
        return refreshAccesToken(resolve); 
       } 
       else { 
        resolve(d.json()); 
       } 
      }); 
    } 

    // Auxiliar server call to get refresh the access token if it is expired. Here also check if the 
    // cookie has expired and if it has expired, then we should redirect to other page to login again in 
    // the application. 
    const refreshAccesToken = (resolve) => { 
     window.fetch(opts.url, { 
      method: 'get', 
      credentials: 'include' 
     }).then((d) => { 
      if (d.status === 401) { 
       // Unauthorized 
       window.location.href = opts.unauthorizedRedirect; 
      } 

      return d.json(); 
     }).then((json) => { 
      const jwt = json.token; 
      if (jwt) { 
       // Store in the browser's storage (sessionStorage by default) the refreshed token, in order to use it on every request 
       opts.storage.setItem(opts.tokenName, jwt); 
       console.log('new acces token: ' + jwt); 

       // Re-send the original request when we have received the refreshed access token. 
       requestResource(resolve); 
      } 
      else { 
       console.log('no token has been sent'); 
       return null; 
      } 
     }); 
    } 

    let promise = new Promise((resolve, reject) => { 
     requestResource(resolve); 
    }); 

    return promise; 
} 

は基本的に、私はPromise作成したと私は、リソースを取得するために、サーバーへの呼び出し関数に内部で呼ばれてきました。ここでcustomFetch.jsファイルのアプローチがあります。私はパラメータ化可能な関数にするために少しrequest(今はrequestResourceと呼ばれています)とrefreshAccessTokenを修正しました。そして、新しいトークンを受け取ったら、機能を "解決"するために私はresolve関数を渡しました。

おそらく解決策を改善して最適化することができますが、最初のアプローチとして期待通りに機能しているため、有効な解決策だと思います。

EDIT:@Dennisが私に示唆したように、私は最初のアプローチで間違いを犯しました。私はちょうどrefreshAccessTokenの機能の中で約束を返さなければなりませんでした。実際には、関数の中にreturn命令を追加しましたが、開始と終了の括弧を削除することもできます)

customFetch.jsファイルはどのように表示する必要がありますか(最初に投稿したコードに似ています。
// 'url' and 'options' parameters are used strictely as you would use them in fetch. 'authOptions' are used to configure the call to refresh the access token 
window.customFetch = (url, options, authOptions) => { 

    const OPTIONS = { 
     url: '', 
     unauthorizedRedirect: '', 
     storage: window.sessionStorage, 
     tokenName: 'accessToken' 
    } 

    // Merge options passed by user with the default auth options 
    let opts = Object.assign({}, OPTIONS, authOptions); 

    // Try to update 'authorizarion's header in order to send always the proper one to the server 
    options.headers = options.headers || {}; 
    options.headers['Authorization'] = `Bearer ${opts.storage.getItem(opts.tokenName)}`; 

    // Actual server request that user wants to do. 
    const request = window.fetch(url, options) 
     .then((d) => { 
      if (d.status === 401) { 
       // Unauthorized 
       console.log('not authorized'); 
       return refreshAccesToken(); 
      } 
      else { 
       return d.json(); 
      } 
     }); 

    // Auxiliar server call to get refresh the access token if it is expired. Here also check if the 
    // cookie has expired and if it has expired, then we should redirect to other page to login again in 
    // the application. 
    const refreshAccesToken =() => { 
     return window.fetch(opts.url, { 
      method: 'get', 
      credentials: 'include' 
     }).then((d) => { 
      // For this example, we can omit this, we can suppose we always receive the access token 
      if (d.status === 401) { 
       // Unauthorized and the cookie used to validate and refresh the access token has expired. So we want to login in to the app again 
       window.location.href = opts.unauthorizedRedirect; 
      } 

      return d.json(); 
     }).then((json) => { 
      const jwt = json.token; 
      if (jwt) { 
       // Store in the browser's storage (sessionStorage by default) the refreshed token, in order to use it on every request 
       opts.storage.setItem(opts.tokenName, jwt); 
       console.log('new acces token: ' + jwt); 

       // Re-send the original request when we have received the refreshed access token. 
       return window.customFetch(url, options, authOptions); 
      } 
      else { 
       console.log('no token has been sent'); 
       return null; 
      } 
     }); 
    } 

    return request; 
} 
+2

ああ、私は遅すぎると思う:DIはここで一組の括弧を取り除くことを提案したいと思った。const refreshAccesToken =()=> window.fetch(...); 'このように' refreshAccesToken'はaを返すべきです約束されていません。すべてが正常に動作しているはずです。 –

+0

@Dennisあなたは正しいです!Yはその機能に間違いを犯し、私は約束を返すのを忘れた。私は試してみましたが、うまくいきましたので、私の答えを編集してあなたのアプローチを追加しました。 – christiansr85

関連する問題