资源“此处的 GUID 值”不存在或其查询的引用属性对象之一不存在

Len*_*rri 1 authentication change-password access-token microsoft-graph-sdks microsoft-graph-api

我正在尝试更改 Azure AD 用户密码。

用户已经使用隐式流和库在SPA应用程序中进行了身份验证。adal

打电话时:

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

我收到此异常:

{"代码:Request_ResourceNotFound\r\n消息:资源“35239a3d-67e3-4560-920a-2e9ce027aeab”不存在或其查询的引用属性对象之一不存在。\r\n\r\n内部错误\r\ n"}

调试我得到的访问令牌,Microsoft Client SDK我看到这个GUID指的是oidsub属性。见下文:

在此处输入图片说明

这是我用来获取令牌的代码:

 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;
Run Code Online (Sandbox Code Playgroud)

我在SPA应用程序中使用隐式流。在这样做时,我看到我的用户已通过身份验证并且所有声明都存在。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" />
Run Code Online (Sandbox Code Playgroud)

我想我没有接近这个正确性,因为我应该为用户获取一个令牌而不是为应用程序获取令牌。我应该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;
Run Code Online (Sandbox Code Playgroud)

但现在我收到错误:

权限不足,无法完成操作。授权请求被拒绝

Len*_*rri 5

经过长时间的调试会话(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;
    }
}
Run Code Online (Sandbox Code Playgroud)

注 1:graphClient.Users[graphUser.ObjectId]正在使用而不是graphClient.Me

注 2:.ToGraphUserAccount()来自 Microsoft.Graph.Auth。

PATCHPostman中有一个示例请求,它为用户正确设置了一个新密码。

在此处输入图片说明

Postman请求标头中使用的访问令牌Authorization与我使用 Microsoft Graph API 获得的相同格式\属性。我只是使用jwt.io比较了它们。所以我一定是叫错了什么...

clientApp.AcquireTokenForClient改用:

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

return authResult.AccessToken;
Run Code Online (Sandbox Code Playgroud)

在哪里:

MSGraphScope = "https://graph.microsoft.com/.default"
Run Code Online (Sandbox Code Playgroud)