在 .Net Core 3.1 中使用 Microsoft Graph 获取用户信息时出现异常

Getting exception while fetching user information using Microsoft Graph in .Net Core 3.1

我在 .net core 3.1 中创建了一个 Web 应用程序并根据 Azure AD 对用户进行身份验证。身份验证成功后,我正在从 Microsoft Graph API 获取用户信息。一切都在本地运行良好,但每当我将其发布到 Azure 时,它​​对于首次登录的用户也运行良好,但如果用户已经登录(先前登录)到 Web 应用程序,则会出现异常。如果已经登录并再次登录的用户注销,则此应用程序也可以正常工作。如果用户已登录并尝试通过 Microsoft Graph 获取用户详细信息,出现异常:

Code: generalException
Message: An error occurred sending the request.
 (1b2e028d)
2021-07-23T03:33:27.7510101+00:00 80010cc2-0000-da00-b63f-84710c7967bb [INF]    at Microsoft.Graph.HttpProvider.SendRequestAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
   at Microsoft.Graph.HttpProvider.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
   at Microsoft.Graph.BaseRequest.SendRequestAsync(Object serializableObject, CancellationToken cancellationToken, HttpCompletionOption completionOption)
   at Microsoft.Graph.BaseRequest.SendAsync[T](Object serializableObject, CancellationToken cancellationToken, HttpCompletionOption completionOption)
   at Microsoft.Graph.UserRequest.GetAsync(CancellationToken cancellationToken)
   at SentimentAnalysisApp.Controllers.HomeController.Index() in D:\Workspaces\Controllers\HomeController.cs:line 70 (15cafa0a)

这是我的 Startup.cs:

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            string[] initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');

            services
            // Use OpenId authentication
            .AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            // Specify this is a web app and needs auth code flow
            .AddMicrosoftIdentityWebApp(Configuration)
            // Add ability to call web API (Graph)
            // and get access tokens
            .EnableTokenAcquisitionToCallDownstreamApi(options =>
            {
                Configuration.Bind("AzureAd", options);
            }, initialScopes)
            // Use in-memory token cache
            // See https://github.com/AzureAD/microsoft-identity-web/wiki/token-cache-serialization
            .AddInMemoryTokenCaches()
            .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"));

            // Require authentication
            services.AddControllersWithViews(options =>
            {
                var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
                options.Filters.Add(new AuthorizeFilter(policy));
            })
            // Add the Microsoft Identity UI pages for signin/out
            .AddMicrosoftIdentityUI();

            //services.AddSingleton<AppData>();
            services.AddScoped<AppData>();
            

            services.AddRazorPages();

            var path = Directory.GetCurrentDirectory();
            services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo($"{path}\DataProtectionKeys\Keys.xml"));

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            var path = Directory.GetCurrentDirectory();
            loggerFactory.AddFile($"{path}\SentimentLogs\Sentiment_Log.txt");

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
                endpoints.MapRazorPages();
            });
        }
    }

这是我的控制器class:

    [Authorize]
    public class HomeController : Controller
    {
    public HomeController(IConfiguration config, ILogger<HomeController> logger,
                              GraphServiceClient graphServiceClient,
                              ITokenAcquisition tokenAcquisition,
                              IDataProtectionProvider provider, AppData appData,
                               IMemoryCache memoryCache)
            {
                _logger = logger;
                _graphServiceClient = graphServiceClient;
                _tokenAcquisition = tokenAcquisition;
                _protector = provider.CreateProtector("Encrypt");
                _appData = appData;
                _config = config;
    
            }
    
            [AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")]
            public async Task<IActionResult> Index()
            {            
                try
                {
                    //Here I'm fetching logged in user details and getting exception if the user 
                    //already logged in.                
                    LoggedInUser = await _graphServiceClient.Me.Request().GetAsync();
                    _appData.LoggedInUser = LoggedInUser.DisplayName;
                    string token = await _tokenAcquisition.GetAccessTokenForUserAsync(GraphConstants.Scopes);                
                }
                catch (MicrosoftIdentityWebChallengeUserException)
                {
                    return Challenge();
                }
                catch (Exception ex)
                {
                    _logger.LogInformation(ex.Message);
                    _logger.LogInformation(ex.StackTrace);
                    Console.WriteLine(ex.Message);
                    //return Challenge();
                }
    
                return View(_appData);
            }
}

如有任何帮助,我们将不胜感激!

我无法根据官方示例代码重现您的问题。但是从你的错误信息来看,我看到你的错误信息来自你的本地电脑。

at SentimentAnalysisApp.Controllers.HomeController.Index() in D:\Workspaces\Controllers\HomeController.cs:line 70 (15cafa0a)

你的描述是本地一切正常,但是release之后,问题就出现了

所以我给出以下建议并建议排错:

  1. 确认门户中是否有本地和 post 发布的 URL

  2. 程序发布时session会被清除,所以在测试功能时,重新发布webapp之前登录的用户会有问题。这是正常的。