我正在开发一个React应用程序,该应用程序将通过ADAL与Azure广告进行身份验证。一切正常,但我需要在应用程序的开头加载JWT令牌。我以为我会包装我的两个函数,这些函数会在Promise中返回一个令牌,然后有条件地呈现它,但是由于某种原因,它不会“等待”我的承诺解决。
任何帮助都将受到欢迎。干杯!
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;
}
答案 0 :(得分:3)
AuthenticationContext#acquireToken
似乎是一个异步方法,它具有一个回调,该回调在获取令牌时(或尝试失败时)被调用。
请考虑重新定义将acquireToken()
括起来的adal helper方法,以使它们成为async
,或者使它们返回Promise
,该回调在回调传递给{{ 1}}被调用:
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}
希望这会有所帮助!
答案 1 :(得分:0)
我建议引入某种加载通知,直到获取令牌为止。您可以等待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
)
}