我有一个非常基本的React App,用户可以登录并点击一些MS Graph端点,一旦用户同意,这将毫无问题。我还有另一个请求触发一个匿名的Azure函数,该函数返回一些JSON,没问题。
我遇到的问题与试图向使用MSAL.js lib的AD锁定的Azure Function Api发出请求有关。
我正在使用https://github.com/sunilbandla/react-msal-sample。
App.js
import React, { Component } from 'react';
import './App.css';
import AuthService from './services/auth.service';
import GraphService from './services/graph.service';
import HelloService from './services/hello.service';
class App extends Component {
constructor() {
super();
this.authService = new AuthService();
this.graphService = new GraphService();
this.helloService = new HelloService();
this.state = {
user: null,
userInfo: null,
apiCallFailed: false,
loginFailed: false
};
}
componentWillMount() {}
callAPI = () => {
this.setState({
apiCallFailed: false
});
this.authService.getToken().then(
token => {
this.graphService.getUserInfo(token).then(
data => {
this.setState({
userInfo: data
});
},
error => {
console.error(error);
this.setState({
apiCallFailed: true
});
}
);
},
error => {
console.error(error);
this.setState({
apiCallFailed: true
});
}
);
};
callHelloAPI = () => {
this.setState({
apiCallFailed: false
});
this.authService.getToken().then(
token => {
this.helloService.callApi(token).then(
data => {
this.setState({
userInfo: data
});
console.log(data);
},
error => {
console.error(error);
this.setState({
apiCallFailed: true
});
}
);
},
error => {
console.error(error);
this.setState({
apiCallFailed: true
});
}
);
};
getTheToken = () => {
console.log('Get Token:');
this.authService.getToken().then(token => {
console.log(token);
});
}
logout = () => {
this.authService.logout();
};
login = () => {
this.setState({
loginFailed: false
});
this.authService.login().then(
user => {
if (user) {
console.log(user);
this.setState({
user: user
});
} else {
this.setState({
loginFailed: true
});
}
},
() => {
this.setState({
loginFailed: true
});
}
);
};
render() {
let templates = [];
if (this.state.user) {
templates.push(
<div key="loggedIn">
<button onClick={this.callAPI} type="button">
Call MS Graph
</button>
<button onClick={this.callHelloAPI} type="button">
Call Azure Function
</button>
<button onClick={this.getTheToken}>
Get The Token (JWT / Cookie)
</button>
<button onClick={this.logout} type="button">
Logout
</button>
<h3>Hello {this.state.user.name}</h3>
<h4>{this.state.user.displayableId}</h4>
</div>
);
} else {
templates.push(
<div key="loggedIn">
<button onClick={this.login} type="button">
Login with Microsoft
</button>
</div>
);
}
if (this.state.userInfo) {
templates.push(
<pre key="userInfo">{JSON.stringify(this.state.userInfo, null, 4)}</pre>
);
}
if (this.state.loginFailed) {
templates.push(<strong key="loginFailed">Login unsuccessful</strong>);
}
if (this.state.apiCallFailed) {
templates.push(
<strong key="apiCallFailed">Graph API call unsuccessful</strong>
);
}
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">React app with MSAL.js</h1>
</header>
{templates}
</div>
);
}
}
export default App;
auth.service
import * as Msal from 'msal';
export default class AuthService {
constructor() {
let PROD_REDIRECT_URI = 'http://localhost:3000/';
let redirectUri = window.location.origin;
if (window.location.hostname !== '127.0.0.1') {
redirectUri = PROD_REDIRECT_URI;
}
this.applicationConfig = {
clientID: 'xxxx-xxxxx-xxxxx-xxxx',
graphScopes: ['user.read','user.readbasic.all']
};
this.app = new Msal.UserAgentApplication(
this.applicationConfig.clientID,
'',
() => {
// callback for login redirect
},
{
redirectUri
}
);
}
login = () => {
return this.app.loginPopup(this.applicationConfig.graphScopes).then(
idToken => {
const user = this.app.getUser();
if (user) {
return user;
} else {
return null;
}
},
() => {
return null;
}
);
};
logout = () => {
this.app.logout();
};
getToken = () => {
return this.app.acquireTokenSilent(this.applicationConfig.graphScopes).then(
accessToken => {
return accessToken;
},
error => {
return this.app
.acquireTokenPopup(this.applicationConfig.graphScopes)
.then(
accessToken => {
return accessToken;
},
err => {
console.error(err);
}
);
}
);
};
}
graph.service
export default class GraphService {
constructor() {
this.graphUrl = 'https://graph.microsoft.com/v1.0/users';
}
getUserInfo = token => {
const headers = new Headers({ Authorization: `Bearer ${token}` });
const options = {
headers
};
return fetch(this.graphUrl, options)
.then(response => response.json())
.catch(response => {
throw new Error(response);
});
};
}
hello.service
export default class HelloService {
constructor() {
this.graphUrl = 'https://xxx.azurewebsites.net/api/Hey';
}
callApi = token => {
const headers = new Headers({ Authorization: `Bearer ${token}` });
const options = {
headers
};
return fetch(this.graphUrl, options)
.then(response => response.json())
.catch(response => {
throw new Error(response);
});
};
}
调用此 hello.service 可以正常工作,但是在被Azure AD应用锁定时返回401。我还从jwt.io验证了JWT令牌。我猜测问题是身份验证问题(希望是一个简单的问题),根据应用程序是仅适用于Azure AD的应用程序还是融合的应用程序,会出现问题吗?我还在功能应用程序本身上启用了CORS。
我的大脑此时已冻结,我不确定朝哪个方向。任何帮助将不胜感激,谢谢。