首页 > 解决方案 > 代码:TokenNotFound 消息:在令牌缓存中找不到用户。可能服务器重启了

问题描述

我有以下功能从活动目录调用用户使用图形 api。此功能在文本框的每个键上都被击中。但我收到以下错误

代码:TokenNotFound 消息:在令牌缓存中找不到用户。也许服务器已重新启动。

在线

var user = await graphClient.Users.Request().GetAsync();

整个函数如下:

     public async Task<string> GetUsersJSONAsync(string textValue)
            {
               // email = email ?? User.Identity.Name ?? User.FindFirst("preferred_username").Value;
                var identifier = User.FindFirst(Startup.ObjectIdentifierType)?.Value;
                var graphClient = _graphSdkHelper.GetAuthenticatedClient(identifier);
                string usersJSON = await GraphService.GetAllUserJson(graphClient, HttpContext, textValue);
                return usersJSON;
            }


    public static async Task<string> GetAllUserJson(GraphServiceClient graphClient, HttpContext httpContext, string textValue)
            {
               // if (email == null) return JsonConvert.SerializeObject(new { Message = "Email address cannot be null." }, Formatting.Indented);

                try
                {
                    // Load user profile.
                    var user = await graphClient.Users.Request().GetAsync();                    
                    return JsonConvert.SerializeObject(user.Where(u => !string.IsNullOrEmpty(u.Surname) && ( u.Surname.ToLower().StartsWith(textValue) || u.Surname.ToUpper().StartsWith(textValue.ToUpper()))), Formatting.Indented);
                }
                catch (ServiceException e)
                {
                    switch (e.Error.Code)
                    {
                        case "Request_ResourceNotFound":
                        case "ResourceNotFound":
                        case "ErrorItemNotFound":
                        //case "itemNotFound":
                        //    return JsonConvert.SerializeObject(new { Message = $"User '{email}' was not found." }, Formatting.Indented);
                        //case "ErrorInvalidUser":
                        //    return JsonConvert.SerializeObject(new { Message = $"The requested user '{email}' is invalid." }, Formatting.Indented);
                        case "AuthenticationFailure":
                            return JsonConvert.SerializeObject(new { e.Error.Message }, Formatting.Indented);
                        case "TokenNotFound":
                            await httpContext.ChallengeAsync();
                            return JsonConvert.SerializeObject(new { e.Error.Message }, Formatting.Indented);
                        default:
                            return JsonConvert.SerializeObject(new { Message = "An unknown error has occured." }, Formatting.Indented);
                    }
                }
            }


 // Gets an access token. First tries to get the access token from the token cache.
        // Using password (secret) to authenticate. Production apps should use a certificate.
        public async Task<string> GetUserAccessTokenAsync(string userId)
        {
            _userTokenCache = new SessionTokenCache(userId, _memoryCache).GetCacheInstance();

            var cca = new ConfidentialClientApplication(
                _appId,
                _redirectUri,
                _credential,
                _userTokenCache,
                null);

            if (!cca.Users.Any()) throw new ServiceException(new Error
            {
                Code = "TokenNotFound",
                Message = "User not found in token cache. Maybe the server was restarted."
            });

            try
            {
                var result = await cca.AcquireTokenSilentAsync(_scopes, cca.Users.First());
                return result.AccessToken;
            }

            // Unable to retrieve the access token silently.
            catch (Exception)
            {
                throw new ServiceException(new Error
                {
                    Code = GraphErrorCode.AuthenticationFailure.ToString(),
                    Message = "Caller needs to authenticate. Unable to retrieve the access token silently."
                });
            }
        }

你能帮忙看看出了什么问题吗?

标签: c#.netasp.net-mvcasp.net-coreazure-active-directory

解决方案


我知道这已经 4 个月大了 - 这对您来说仍然是个问题吗?

正如前面的受访者所指出的,您看到的错误被抛出在代码中的 catch 块中,用于处理空的 users 集合。

如果你被困在这个问题上,或者其他人来到这里 - 如果你使用了这个示例(或ConfidentialClientApplication在任何方面使用)并抛出这个异常,那是因为你的 _userTokenCache 没有用户*。当然不是因为你的AD没有用户,否则你就无法认证。很可能是因为您的浏览器中的一个陈旧的 cookie 作为访问令牌传递给您的 authProvider。您可以使用 Fiddler(或仅检查您的 localhost 浏览器 cookie)来找到它(应该称为 AspNetCore.Cookies,但您可能需要清除所有这些)。

如果您将令牌缓存存储在会话中(如示例所示),请记住每次启动和停止应用程序时,您的工作内存都会被丢弃,因此您的浏览器提供的令牌将不再匹配您的应用程序的新令牌将在重新启动时检索(除非您再次清除了浏览器 cookie)。

* cca.UsersMSAL 不再使用或支持 - 您必须使用cca.GetAccountsAsync(). 如果您有一个使用已弃用的实现运行的已部署应用程序,则IUser必须更改它。否则,在开发过程中,您的编译器会抱怨并且不允许您构建,因此您已经知道这一点。


推荐阅读