问题
I have a Single Page App (SPA) written in ReactJS. I am attempting to query the Graph API. I am using the msal.js library to handle my authentication. I am using Azure AD B2C to manage my accounts. What I have so far:
I am able to login to Google and get my profile information back to my SPA. However, when an accessToken is requested, the result is empty. I am positive I'm doing something wrong and I'm guessing it's around my app registration and scopes. When I registered my app, it had a default scope called "user_impersonation". As I type this, I realize I registered my client (SPA) and not the API. Do I need to register both? I'm not sure how I would register Graph.
My code:
App.js
import AuthService from '../services/auth.service';
import GraphService from '../services/graph.service';
class App extends Component {
constructor() {
super();
this.authService = new AuthService();
this.graphService = new GraphService();
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
});
}
);
};
logout = () => {
this.authService.logout();
};
login = () => {
this.setState({
loginFailed: false
});
this.authService.login().then(
user => {
if (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 Graph's /me API
</button>
<button onClick={this.logout} type="button">
Logout
</button>
<h3>Hello {this.state.user.name}</h3>
</div>
);
} else {
templates.push(
<div key="loggedIn">
<button onClick={this.login} type="button">
Login with Google
</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 />
<Main />
{templates}
</div>
);
}
}
export default App
auth.service.js:
import * as Msal from 'msal';
export default class AuthService {
constructor() {
// let PROD_REDIRECT_URI = 'https://sunilbandla.github.io/react-msal-sample/';
// let redirectUri = window.location.origin;
// let redirectUri = 'http://localhost:3000/auth/openid/return'
// if (window.location.hostname !== '127.0.0.1') {
// redirectUri = PROD_REDIRECT_URI;
// }
this.applicationConfig = {
clientID: 'my_client_id',
authority: "https://login.microsoftonline.com/tfp/my_app_name.onmicrosoft.com/b2c_1_google-sisu",
b2cScopes: ['https://my_app_name.onmicrosoft.com/my_api_name/user_impersonation email openid profile']
// b2cScopes: ['graph.microsoft.com user.read']
};
this.app = new Msal.UserAgentApplication(this.applicationConfig.clientID, this.applicationConfig.authority, function (errorDesc, token, error, tokenType) {});
// this.logger = new Msal.logger(loggerCallback, { level: Msal.LogLevel.Verbose, correlationId:'12345' });
}
login = () => {
return this.app.loginPopup(this.applicationConfig.b2cScopes).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.b2cScopes).then(
accessToken => {
return accessToken;
},
error => {
return this.app
.acquireTokenPopup(this.applicationConfig.b2cScopes)
.then(
accessToken => {
return accessToken;
},
err => {
console.error(err);
}
);
}
);
};
}
graph.service.js
export default class GraphService {
constructor() {
// this.graphUrl = 'https://graph.microsoft.com/v1.0';
this.graphUrl = 'http://httpbin.org/headers';
}
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.text());
});
};
}
I was getting an access denied error when trying to query the Graph API so I replaced graph.microsoft.com/1.0 with httpbin so I could actually see what was being passed in. This is where I saw that the token was null. This is the exact same code I pulled from Microsoft's example project, which works when I use their code. What they don't show is how AAD B2C and app registrations are configured which is where I believe my problem is.
回答1:
Sorry, it may be a bit confusing for users, but there are several different services here.
There is Azure AD Graph API - it is same for B2C
There is Microsoft Graph.
Then, within Azure AD B2C itself, you have your Application Registration for the B2C part. Using this application registration you cannot use any of the Graphs.
There is also a normal Application Integration in Azure Active Directory which is valid for the Graphs. However this type of application integrations (also as described here) cannot be used for B2C flows.
So, to make it clear again:
You cannot use any of the Graph APIs (neither Azure AD Graph API nor Microsoft Graph) from the context of an B2C application.
AND
You cannot use any B2C functionality (like login with google, etc.) from the context of "normal" app registered for use with Graph.
So, in context of B2C registered application you can only request and get an access_token for an API which is also registered for use with B2C.
回答2:
My problem was I needed to register 2 applications: 1 for my client, 1 for the API. Then, in the Azure AD B2C portal, I had to grant the client access to the API. Once I did that, an Access Token was given.
来源:https://stackoverflow.com/questions/50959353/azure-ad-b2c-not-getting-access-token