Ресурс "Здесь значение GUID" не существует или отсутствует один из запрошенных объектов свойства ссылки

Я пытаюсь изменить пароль пользователя Azure AD.

Пользователь уже аутентифицирован в приложении СПА с использованием неявный поток и библиотеки adal.

Во время вызова:

return await graphClient.Me.Request().UpdateAsync(new User
                {
                    PasswordProfile = new PasswordProfile
                    {
                        Password = userPasswordModel.NewPassword,
                        ForceChangePasswordNextSignIn = false
                    },
                });

Я получаю это исключение:

{"Code: Request_ResourceNotFound\r\nMessage: Resource '35239a3d-67e3-4560-920a-2e9ce027aeab' does not exist or one of its queried reference-property objects are not present.\r\n\r\nInner error\r\n"}

При отладке токена доступа, который я получил с помощью Microsoft Client SDK, я вижу, что этот GUID относится к свойствам oid и sub. Смотри ниже:

Ресурс "Здесь значение GUID" не существует или отсутствует один из запрошенных объектов свойства ссылки

Это код, который я использую для получения токена:

 IConfidentialClientApplication clientApp =
     ConfidentialClientApplicationBuilder.Create(Startup.clientId)
            .WithAuthority(string.Format(AuthorityFormat, Startup.tenant))
            .WithRedirectUri(Startup.redirectUri)
            .WithClientSecret(Startup.clientSecret)
            .Build();

            var authResult = await clientApp.AcquireTokenForClient(new[] { MSGraphScope }).ExecuteAsync();

            return authResult.AccessToken;

Я использую неявный поток в приложении СПА. При выполнении ClaimsPrincipal.Current я вижу, что мой пользователь аутентифицирован и все претензии присутствуют.

Я прочитал много документов @ GitHub и Microsoft Docs, но до сих пор не понимаю, как это реализовать. Кстати, я использую эти пакеты Microsoft Graph:

  <package id = "Microsoft.Graph" version = "1.15.0" targetFramework = "net461" />
  <package id = "Microsoft.Graph.Auth" version = "0.1.0-preview.2" targetFramework = "net461" />
  <package id = "Microsoft.Graph.Core" version = "1.15.0" targetFramework = "net461" />

Я предполагаю, что я не подхожу к этому корректно, потому что вместо того, чтобы приобретать токен для приложения, я должен получить токен для пользователя. Должен ли я использовать clientApp.AcquireTokenOnBehalfOf вместо этого?

Если да, то каков рекомендуемый способ получения маркера для текущего пользователя, вошедшего в систему, с помощью Microsoft Graph API SDK?

Можете ли вы пролить свет?

####### РЕДАКТИРОВАТЬ #######

Я смог добиться некоторого прогресса, используя это:

var bearerToken = ClaimsPrincipal.Current.Identities.First().BootstrapContext as string;

JwtSecurityToken jwtToken = new JwtSecurityToken(bearerToken);

var userAssertion = new UserAssertion(jwtToken.RawData, "urn:ietf:params:oauth:grant-type:jwt-bearer");

IEnumerable<string> requestedScopes = jwtToken.Audiences.Select(a => $"{a}/.default");

var authResult = clientApp.AcquireTokenOnBehalfOf(new[] { MSGraphScope }, userAssertion).ExecuteAsync().GetAwaiter().GetResult();

return authResult.AccessToken;

но теперь я получаю сообщение об ошибке:

insufficient privileges to complete the operation. authorization_requestdenied

Сразу после публикации этого вопроса я нашел этот github.com/AzureAD/microsoft-authentication-library-for-dotn‌​et/…

Leniel Maccaferri 11.06.2019 17:37

Я немного запутался. Вы упомянули об использовании неявного гранта OAuth, но токен, который вы получаете, содержит Roles, а не scp. Роли — это приложения (учетные данные клиента), что подразумевает, что вы не используете здесь неявный. То, что вы хотите, - это неявное использование области Directory.AccessAsUser.All.

Marc LaFleur 12.06.2019 21:34

Просто чтобы уточнить, области приложения (roles) нельзя использовать для сброса паролей пользователей. Только делегированные области поддерживают сброс паролей. Это гарантирует, что любой сброс пароля может быть проверен для конкретного пользователя («глоток, чтобы задохнуться», как они говорят).

Marc LaFleur 12.06.2019 21:38

@MarcLaFleur Спасибо, что заглянули и разъяснили. Я прибегнул к использованию оригинального clientApp.AcquireTokenForClient вместо clientApp.AcquireTokenOnBehalfOf. Написал ответ ниже.

Leniel Maccaferri 12.06.2019 21:57
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
1 768
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

После долгого сеанса отладки (8 часов или около того) я наконец смог получить то, что хотел, после того, как увидел этот ответ от @Michael Mainer.

Это "правильный" код, который я собрал:

public async Task<User> ChangeUserPassword(UserPasswordModel userPasswordModel)
{
    try
    {
        var graphUser = ClaimsPrincipal.Current.ToGraphUserAccount();

        var newUserInfo = new User()
        {
            PasswordProfile = new PasswordProfile
            {
                Password = userPasswordModel.NewPassword,
                ForceChangePasswordNextSignIn = false
            },
        };

        // Update the user...
        return await graphClient.Users[graphUser.ObjectId].Request().UpdateAsync(newUserInfo);
    }
    catch(Exception e)
    {
        throw e;
    }
}

Note 1: graphClient.Users[graphUser.ObjectId] is being used instead of graphClient.Me

Note 2: .ToGraphUserAccount() is from Microsoft.Graph.Auth.

У меня был пример запроса PATCH в Почтальон, который правильно установил новый пароль для пользователя.

Токен доступа, используемый в заголовке запроса Postman Authorization, имел тот же формат\свойства, что и тот, который я получал с помощью Microsoft Graph API. Я только что сравнил их, используя jwt.io. Значит, я что-то неправильно назвал...

Вместо этого я использовал clientApp.AcquireTokenForClient:

var authResult = await clientApp.AcquireTokenForClient(new[] { MSGraphScope }).ExecuteAsync();

return authResult.AccessToken;

куда:

MSGraphScope = "https://graph.microsoft.com/.default"

Другие вопросы по теме