资源“此处的GUID值”不存在,或者其查询的参考属性对象之一不存在

时间:2019-06-11 15:21:47

标签: authentication microsoft-graph access-token change-password microsoft-graph-sdks

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

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

调用时:

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

我遇到此异常:

  

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

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

enter image description here

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

 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;

我正在 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" />

我想我并没有解决这个问题,因为我应该为用户获取令牌,而不是为应用程序获取令牌。我应该改用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;

但是现在我得到了错误:

  

权限不足,无法完成操作。   authorization_requestdenied

1 个答案:

答案 0 :(得分:2)

经过长时间的调试(大约8个小时),在看到@Michael Mainer的this answer之后,我终于能够得到想要的东西。

这是我编写的“正确”代码:

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;
    }
}
  

注意1:使用graphClient.Users[graphUser.ObjectId]代替graphClient.Me

     

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

我在Postman中有一个示例PATCH请求,可以为用户正确设置新密码。

enter image description here

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"