代表已登录的用户从MVC连接到Microsoft Graph [英] Connect to Microsoft Graph from MVC on behalf of logged in user

查看:79
本文介绍了代表已登录的用户从MVC连接到Microsoft Graph的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个MVC Web应用程序,该应用程序具有某些页面,需要用户登录.该应用程序是多租户,并且在Startup.Auth.cs中配置了身份验证. ConfigureAuth文件如下所示:

I have created an MVC web app, that has certain pages that require a user to be logged in. The app is multitenant, and the authentication is configured in the Startup.Auth.cs. The ConfigureAuth file looks like this:

public void ConfigureAuth(IAppBuilder app){
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions());

    app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions {
        ClientId = clientId,
        Authority = authority,
        RedirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"],                
        TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters{
            ValidateIssuer = false,
        },
        Notifications = new OpenIdConnectAuthenticationNotifications(){
            SecurityTokenValidated = (context) => {
                return Task.FromResult(0);
            },
            AuthorizationCodeReceived = (context) => {
                var code = context.Code;

                ClientCredential credential = new ClientCredential(clientId, appKey);
                string tenantID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
                string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
                AuthenticationContext authContext = new AuthenticationContext(
                    aadInstance + tenantID,
                    new ADALTokenCache(signedInUserID)
                );
                AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
                    code,
                    new Uri(ConfigurationManager.AppSettings["ida:RedirectUri"]),
                    credential,
                    graphResourceID
                );

                return Task.FromResult(0);
            },
            AuthenticationFailed = (context) => {
                context.HandleResponse(); // Suppress the exception
                context.Response.Redirect("/Error?message=" + context.Exception.Message);
                return Task.FromResult(0);
            }
        }
    });
}

这有效-完美.我的问题是,当我调用Microsoft Graph端点时,我希望在控制器中对此具有相同的授权.

This works - perfectly. My problem is, I would love to this the same authorization in my controller, when calling a Microsoft Graph endpoint.

我可以看到AuthenticationResult中包含的AccessToken具有正确的作用域-这意味着我应该能够在调用Graph时重用它,对吧?

I can see that the AccessToken contained in the AuthenticationResult has the correct scopes - meaning I should be able to reuse this when calling Graph, right?

但是如何在控制器中使用它呢?以及如何确保令牌被刷新?

But how do I use this in my controller? And how do I ensure the token is refreshed?

我可以找到的所有示例都可以将MSAL与v2端点一起使用,或者代表客户端进行连接-这对我不起作用.

All examples I can find either use MSAL with v2 endpoint, or connects on behalf of the client - this does not work for me.

推荐答案

您不能在控制器内部重用令牌并将其发送给图形,以使图形认为您是用户.这不起作用,因为令牌还包含客户端的IP地址,而不是控制器运行的IP地址(可能仅在开发人员机器上).相反,您的应用程序必须具有Directory.AccessAsUser.All权限.

You cannot reuse the token from within your controller and send it to graph so that graph thinks you are the user. This doesn't work, cause the token also contains the ip address of the client and that is not the ip address where your controller runs (well maybe only on your developer machine). Instead your application must have the Directory.AccessAsUser.All permission.

如果有这个,可以在后端中创建一个

If you have this, within your backend you can create a

new AuthenticationContext("https://login.microsoftonline.com/common/")

并调用 AuthenticationContext.AcquireTokenAsync(scope, clientCredentials, userAssertation) .

  • 在这种情况下,scope必须为https://graph.microsoft.com/.
  • clientCredentials必须包含您的应用程序ID和密码.
  • userAssertation必须包含
    • 用户令牌为断言
    • 类型应为urn:ietf:params:oauth:grant-type:jwt-bearer
    • 用户名必须是用户UPN
    • In this case the scope has to be https://graph.microsoft.com/.
    • clientCredentials must contain your application id and secret.
    • userAssertation must contain
      • the user token as assertation
      • the type should be urn:ietf:params:oauth:grant-type:jwt-bearer
      • the username must be the users UPN

      此呼叫返回时,您将获得一个新令牌.可以在图形调用中将其用作控制器代码中的承载令牌,以访问资源,就像用户自己会这样做一样.

      When this call returns, you'll get a new token. This can be used in graph calls as bearer token from your controller code to access resources as the user itself would do it.

      但是请确保该令牌不会泄漏到您的控制之外(例如应用程序密码).因为只要此令牌没有过期,它就可以在世界上的任何计算机上用作用户.

      But ensure that this token doesn't leak out of your control (like the application secret). Cause as long as this token doesn't expire it can be used from any machine in the world to act as the user.

      如果没有用户令牌,则需要一个应用程序令牌来访问图形api.根据 https://docs.microsoft.com/zh-CN/azure/active-directory/develop/v2-oauth2-auth-code-flow ,您可以通过调用获取应用程序的令牌

      If you don't have a user token, you need an application token to access the graph api. According to https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow you can get a token for your application by calling

      using (var client = new HttpClient())
      {
          var content = new Dictionary<string, string>
          {
              { "grant_type", "client_credentials" },
              { "scope", "https://graph.microsoft.com/.default"},
              { "client_id", "<ApplicationId>" },
              { "client_secret", "<ApplicationSecret>" }
          };
      
          var response = await client.PostAsync($"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token", content);
          var content = await response.Content.ReadAsStringAsync();
          dynamic answer = JObject.Parse(content);
      
          return answer.access_token;
      }
      

      当您将此令牌发送给前缀为Bearer的授权标头中的图形时,您应该能够访问给定租户中已授予您的应用程序的所有资源.

      When you send this token to graph in the authorization header with the prefix Bearer you should be able to access all resources within the given tenant, which have been granted to your application.

      这篇关于代表已登录的用户从MVC连接到Microsoft Graph的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆