ClaimsPrincipal.Current.FindFirst (ClaimTypes.NameIdentifier). Значение не возвращает никакого значения - PullRequest
0 голосов
/ 09 мая 2018

Я создаю веб-приложение mvc для чтения почты пользователя, отправки почты пользователю и получения уведомлений с помощью Microsoft Graph Api. Мое приложение зарегистрировано в https://apps.dev.microsoft.com. Я могу получить возвращаемое значение для "ClaimsPrincipal.Current.FindFirst (ClaimTypes.NameIdentifier) ​​.Value" после входа в систему и после подписки на уведомления. Но я не могу получить возвращаемое значение внутри функции Listen (), которая используется для прослушивания уведомлений. «Ссылка на объект не установлена ​​для экземпляра объекта» - это заданная ошибка. Это функция Listen ().

public async Task<ActionResult> Listen()
    {
        // Validate the new subscription by sending the token back to Microsoft Graph.
        // This response is required for each subscription.
        if (Request.QueryString["validationToken"] != null)
        {               
            var token = Request.QueryString["validationToken"];
            return Content(token, "plain/text");
        }

        // Parse the received notifications.
        else
        {

            try
            {
                var notifications = new Dictionary<string, NotificationModel>();
                using (var inputStream = new System.IO.StreamReader(Request.InputStream))
                {
                    JObject jsonObject = JObject.Parse(inputStream.ReadToEnd());
                    if (jsonObject != null)
                    {

                        // Notifications are sent in a 'value' array. The array might contain multiple notifications for events that are
                        // registered for the same notification endpoint, and that occur within a short timespan.
                        JArray value = JArray.Parse(jsonObject["value"].ToString());
                        foreach (var notification in value)
                        {
                            NotificationModel current = JsonConvert.DeserializeObject<NotificationModel>(notification.ToString());

                            // Check client state to verify the message is from Microsoft Graph. 
                            SubscriptionStore subscription = SubscriptionStore.GetSubscriptionInfo(current.SubscriptionId);

                            // This sample only works with subscriptions that are still cached.
                            if (subscription != null)
                            {
                                if (current.ClientState == subscription.ClientState)
                                {

                                    // Just keep the latest notification for each resource.
                                    // No point pulling data more than once.
                                    notifications[current.Resource] = current;
                                }
                            }
                        }

                        if (notifications.Count > 0)
                        {

                            // Query for the changed messages. 
                         await GetChangedMessagesAsync(notifications.Values);

                        }
                    }
                }
            }
            catch (Exception)
            {
                // TODO: Handle the exception.
                // Still return a 202 so the service doesn't resend the notification.
            }

            return new HttpStatusCodeResult(202);
        }
    }

    // Get information about the changed messages and send to the browser via SignalR.
    // A production application would typically queue a background job for reliability.
    public async Task GetChangedMessagesAsync(IEnumerable<NotificationModel> notifications)
    {
        List<MessageViewModel> messages = new List<MessageViewModel>();
        MessageModel message = new MessageModel();
        string serviceRootUrl = "https://graph.microsoft.com/v1.0/";
        foreach (var notification in notifications)
        {
            SubscriptionStore subscription = SubscriptionStore.GetSubscriptionInfo(notification.SubscriptionId);
            string token;
            try
            {
                // Get the access token for the subscribed user.
                // accessToken = await GetAccessToken();
                HttpContextBase httpContext = HttpContext;
                token = await AuthHelper.GetAccessToken(httpContext);
            }
            catch (Exception e)
            {
                throw e;
            }

            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, serviceRootUrl + notification.Resource);

            // Send the 'GET' request.
            GraphHttpClient graphHttpClient = new GraphHttpClient(token);
            HttpResponseMessage response = await graphHttpClient.SendAsync(request);

            // Get the messages from the JSON response.
            if (response.IsSuccessStatusCode)
            {
                string stringResult = await response.Content.ReadAsStringAsync();
                string type = notification.ResourceData.ODataType;
                if (type == "#Microsoft.Graph.Message")
                {
                    message = JsonConvert.DeserializeObject<MessageModel>(stringResult);
                    MessageViewModel messageViewModel = new MessageViewModel(message);
                    messages.Add(messageViewModel);                       
                }
            }
        }
        if (messages.Count > 0)
        {
            NotificationService notificationService = new NotificationService();
            notificationService.SendNotificationToClient(messages);  


        }



    }

Это метод GetAccessToken (), в котором используется «ClaimsPrincipal.Current.FindFirst (ClaimTypes.NameIdentifier) ​​.Value».

public static async Task<string> GetAccessToken(HttpContextBase HttpContext)
    {
        string accessToken = string.Empty; ;
        // Load the app config from web.config
        string appId = ConfigurationManager.AppSettings["ida:AppId"];
        string appPassword = ConfigurationManager.AppSettings["ida:AppPassword"];
        string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
        string[] scopes = ConfigurationManager.AppSettings["ida:AppScopes"]
            .Replace(' ', ',').Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

        string userId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;

            if (!string.IsNullOrEmpty(userId))
            {
                // Get the user's token cache
                SessionTokenCache tokenCache = new SessionTokenCache(userId, HttpContext);

                ConfidentialClientApplication cca = new ConfidentialClientApplication(
                    appId, redirectUri, new Microsoft.Identity.Client.ClientCredential(appPassword), tokenCache.GetMsalCacheInstance(), null);


                // Call AcquireTokenSilentAsync, which will return the cached
                // access token if it has not expired. If it has expired, it will
                // handle using the refresh token to get a new one.
                AuthenticationResult result = await cca.AcquireTokenSilentAsync(scopes, cca.Users.FirstOrDefault());

                accessToken = result.AccessToken;
            }

        // Get the current user's ID           

        return accessToken;
    }

1 Ответ

0 голосов
/ 11 мая 2018

Я думаю, что вы говорите, что вы не получаете идентификационные данные пользователя из промежуточного программного обеспечения OWIN на вашей конечной точке уведомления. Вы не должны ожидать этого! Ваша конечная точка уведомления получает сообщения POSTS от службы Office 365, которая не работает как какой-либо конкретный пользователь. Он включает токен на предъявителя в заголовок Authorization, который вы можете использовать для проверки подлинности от Microsoft, но это так.

Вы должны сопоставлять идентификаторы подписки с идентификаторами пользователей на вашей стороне. Таким образом, когда приходит уведомление, вы можете соотнести. Вы также не хотели бы использовать кеш токена на основе сеанса в этом сценарии. Вместо этого вы захотите иметь что-то более глобально доступное для вашего приложения, например, базу данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...