问题
I am developing an API(ASP.NET Core) which is accessed via separately hosted web client(React), both hosted on azure as app services. Client app must have auth based on azure Ad(single tenant, preferably secured by azure auth based on aad). When the user signs in to client the API must have access to MS Graph on behalf of user. Obviously both resources must be secured, I have tried using azure auth based on AAD on both app services, but I couldn't get a token to MsGraph in this approach with the token obtained from auth to ADD on API side.
Question is, how to avoid passing token to MsGraph with token for azure aad auth from client, and obtain token for msGraph based only on token from aad auth while having only one place for users to sign in and keep both app services secured?
I am using nugget for MsGraph on Api side to interact with MsGraph. I haven't found any sample that refers this specific case.
回答1:
Scenario: Your application's Web API (protected by Azure AD) receives auth token from a client application (React) and needs to call a downstream Web API (Microsoft Graph) on behalf of the signed-in User.
Conceptual Documentation on Microsoft Docs: Your scenario exactly matches the OAuth 2.0 on-behalf-of flow as explained on Microsoft Docs for Azure AD here Service-to-service calls that use delegated user identity in the On-Behalf-Of flow
Code Samples:
- Service to service calls on behalf of the user (From Azure-Samples on GitHub)
- Calling a downstream web API from a web API on behalf of user (From Azure-Samples on GitHub)
- Using Azure AD On-Behalf-Of flow in an ASP.NET Core 2.0 API (Not directly Microsoft samples, but from Joonas W's blog, who is an MVP)
Important Code
This is how you use the already passed in token to acquire a new token, with which to call the Microsoft Graph API, from your Web API, on behalf of the user.
Preparing the User Assertion:
ClientCredential clientCred = new ClientCredential(clientId, appKey);
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
string userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
string userAccessToken = bootstrapContext.Token;
UserAssertion userAssertion = new UserAssertion(userAccessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
Acquiring a token for Microsoft Graph:
result = await authContext.AcquireTokenAsync(graphResourceId, clientCred, userAssertion);
回答2:
I ended up with using only Azure Ad + auth validation by code(no azure auth). The API uses OBO flow, the client app uses implicit flow.
Basically two separate app registrations on aad, the client which has access_as_user permision to the api, and the other one for api which has permissions for MsGraph. You configure it in App registrations(preview)/API permissions. (For detailed guide follow examples below, start with the api)
For Web client I also used scopes: 'access_as_user', 'offline_access', 'openid' in the request for the token, added true for "oauth2AllowImplicitFlow" in manifest and redirect to the yourdomainname.azurewebsites.com, the rest of configuration similarly to the native client in example below.
Useful resources:
API:
https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2 https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-on-behalf-of-flow
(I recommend testing with native client first to check if its set up correctly, configuration of API will remain the same for separate web client)
Web client:
https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-implicit-grant-flow
This is solution which suits me at the moment, it might be possible to tailor it better.
来源:https://stackoverflow.com/questions/53732255/accessing-ms-graph-from-api-on-behalf-of-user-currently-signed-in-to-separate-we