ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value不返回任何值

时间:2018-05-09 12:19:55

标签: microsoft-graph

我正在创建一个mvc Web应用程序来读取用户邮件,向用户发送邮件以及使用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 :(得分:0)

我认为您所说的是您没有从通知端点上的OWIN中间件获取用户身份。你不应该期待一个!您的通知端点从Office 365服务接收POSTS,该服务未以任何特定用户身份运行。它确实包含Authorization标头中的承载令牌,您可以使用它来验证它是否真的来自Microsoft,但就是这样。

您应该将订阅ID映射到您身边的用户ID。这样,当收到通知时,您可以进行关联。您也不希望在该场景中使用基于会话的令牌缓存。相反,您希望您的应用程序可以全局访问某些内容,例如数据库。