Javascript обещание ждет результата - PullRequest
0 голосов
/ 06 февраля 2019

Я разрабатываю приложение React, которое будет проходить аутентификацию с помощью Azure Ad через ADAL.Все работает нормально, но мне нужно загрузить токены JWT в начале приложения.Я думал, что оберну свои две функции, которые возвращают токен в Обещании, а затем условно отображает его, однако по какой-то причине он не «ждет», пока мое обещание не будет выполнено.

Любая помощь будет приветствоваться.Ура!

import React, { Component } from 'react';

import { library } from '@fortawesome/fontawesome-svg-core';
import { faIgloo, faBars } from '@fortawesome/free-solid-svg-icons';
import { initializeIcons } from '@uifabric/icons';
import { acquireToken, acquireGraphToken } from '../../adalConfig'

import Navbar from '../../common/navbar/navbar';
import Searchbar from '../../common/utils/searchBar/searchBar';
import LeftNavigation from '../../common/leftNavigation/leftNavigation';
import PageContainer from '../pageContainer/pageContainer';
import { IntlProvider } from 'react-intl';

import messages_en from '../../assets/translations/translations_en';
import messages_nl from '../../assets/translations/translations_nl';
import StylesheetLoader from '../../common/utils/stylesheetLoader/stylesheetLoader';
import ReactAI from 'react-appinsights';
import { connect } from 'react-redux';
import * as userActions from '../../store/users/actions';

initializeIcons();
library.add(faIgloo, faBars);

class App extends Component {

  state = {
    languageChoice: 'en',
    theme: 'red',
    tokensAreLoaded: false
  }

  componentWillMount() {

    let promise = new Promise((resolve, reject) => {
      const token = acquireToken();
      const graphToken = acquireGraphToken();

      if (token != '' && graphToken != '') {
        resolve(true);
      } else {
        reject(Error('promise failed'))
      }
    });

    promise.then( (value) => {
      this.setState({tokensAreLoaded: value});
    }, function (error){
      console.log('error getting promise value');
    })
  }

  componentDidMount() {
    this.props.onFetchCurrentUser();
  }    

  render() {

    if (this.state.tokensAreLoaded) {
      console.log('renderApp');
    } else {
      console.log('loading');
    }

    // Sets an interval that refreshes to get the token every 15 minutes
    // We use this because our custom API's do not automatically issue a
    // refresh token.
    setInterval(AppTokenRefresher, 900000);

    function AppTokenRefresher() {
      acquireToken();
      acquireGraphToken();
    } 

    const messages = {
        'nl': messages_nl,
        'en': messages_en
    };

    ReactAI.setAppContext({urlReferrer: document.referrer});
    // const Ai = ReactAI.ai();

    // function test() {
    //   Ai.trackEvent('Testing', { 'user': 'me' });
    // }

    const user = this.props.currentUser ? this.props.currentUser.name : 'test';

    return (
      <React.Fragment>
        <StylesheetLoader />
        {user}
        <IntlProvider locale={this.state.languageChoice} messages={messages[this.state.languageChoice]}>
          <div className="siteContainer">
            <Navbar currentUserProfile={this.props.currentUser}></Navbar>

            <div className="mobile-searchbar">
              <Searchbar />
            </div>

            <div className='page-container'>
              <aside>
                <LeftNavigation />
              </aside>

              <section className="main">
                <PageContainer />
            </section>

            </div>

          </div>
        </IntlProvider>

      </React.Fragment>
    );
  }
}

const mapStateToProps = state => {
  return {
      currentUserError: state.currentUserSlice.currentUserError,
      currentUserLoading: state.currentUserSlice.currentUserLoading,
      currentUser: state.currentUserSlice.currentUser,
      currentUserPicture: state.currentUserSlice.currentUserPicture
  }
}

const mapDispatchToProps= (dispatch) => {
  return {
      onFetchCurrentUser: () => dispatch(userActions.fetchCurrentUser()),
      onFetchCurrentUserPicture: () => dispatch(userActions.fetchCurrentUserPicture())
  }    
}

export default connect(mapStateToProps, mapDispatchToProps)(App);

Вспомогательные функции Adal, которые я включаю в обещание:

import { AuthenticationContext, adalFetch } from 'react-adal';

const adalConfig = {
    instance: 'https://login.microsoftonline.com/',
    clientId: '9e16003a',
    extraQueryParameter: 'nux=1',
    endpoints: {
        graphApi: 'https://graph.microsoft.com',
        oneApi: 'https://one365demo.onmicrosoft.com/b15a-3f1d0cf658f5'
    },
    postLogoutRedirectUri: window.location.origin,
    redirectUri: window.location.origin,
    cacheLocation: 'localStorage'
};

export const authContext = new AuthenticationContext(adalConfig);



export const adalGraphFetch = (fetch, url, options) =>
  adalFetch(authContext, adalConfig.endpoints.graphApi, fetch, url, options);

export const adalOneApiFetch = (fetch, url, options) =>
  adalFetch(authContext, adalConfig.endpoints.oneApi, fetch, url, options);

export const getToken = () => {
    return authContext.getCachedToken(authContext.config.clientId);
};

export const getGraphToken = () => {
    return authContext.getCachedToken('https://graph.microsoft.com');
};

export const acquireGraphToken = () => {  
    authContext.acquireToken(adalConfig.endpoints.graphApi, (message, token, msg) => {
        console.log('graph token', token);
        return token;
    })

    return null;
} 

export const acquireToken = () => {  
    authContext.acquireToken(adalConfig.endpoints.oneApi, (message, token, msg) => {
        console.log('the token', token);
        return token;
    })

    return null;
}

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Я бы рекомендовал вводить какое-то уведомление о загрузке, пока токен не будет выбран.Вы можете ожидать токен в componentDidMount, чтобы не блокировать стек

async componentDidMount() {
    try {
        const token = await this.getToken();
        this.setState({tokensAreLoaded: true, token});
    } catch (e) {
        throw new Error (e);
    }
}
getToken () {
    return new Promise((resolve, reject) => {
        const token = acquireToken();
        const graphToken = acquireGraphToken();

        if (token != '' && graphToken != '') {
            resolve(token);
        } else {
           reject(Error('promise failed'))
        }
    });
}

А в вашем render методе:

render () {
    if (!this.state.tokensAreLoaded) {
        return (<p>Authorizing</p>);
    }
    return (
       // the stuff you want to display when token is ready
    )

}
0 голосов
/ 06 февраля 2019

Похоже, AuthenticationContext#acquireToken - это асинхронный метод, в котором есть обратный вызов, который вызывается при получении токена (или при неудачной попытке сделать это).

Рассмотрите возможность переопределения помощника adalметоды, которые заключают вызов в acquireToken() так, чтобы они были либо async, либо чтобы они возвращали Promise, который прогрессирует при вызове обратного вызова, переданного в AuthenticationContext#acquireToken():

export const acquireGraphToken = () => {  

    /* Return promise as acquireToken() is async */
    return (new Promise(resolve => {
        authContext.acquireToken(adalConfig.endpoints.graphApi, (message, token, msg) => {
                console.log('graph token', token);

                /* Resolve enclosing promise with token */
                resolve(token); 
            })
        }));    
} 

export const acquireToken = () => {  

    /* Return promise as acquireToken() is async */
    return (new Promise(resolve => {
        authContext.acquireToken(adalConfig.endpoints.oneApi, (message, token, msg) => {
            console.log('the token', token);

            /* Resolve enclosing promise with token */
            resolve(token); 
        })
    }));
}

сэти изменения, примененные в вашем вспомогательном модуле, вам нужно будет обновить хук компонента componentWillMount(), чтобы правильно интегрировать эти методы, чтобы гарантировать, что состояние компонента обновляется с {tokensAreLoaded: true} после успешного получения обоих токенов:

componentWillMount() {

    /* Issue request for both tokens to get aquired */
    Promise.all([
        acquireToken(),
        acquireGraphToken()
    ])
    .then(([ token, graphToken ]) => {

        /* On resolving both requests, ensure tokens are value before proceeding or reject (as before) */
        if (token != '' && graphToken != '') {
            resolve(token);
        } else {
            reject(Error('promise failed'))
        }
    })
    .then(() => {

        /* On success, update state */
        this.setState({tokensAreLoaded: true});
    })
  }

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...