Oauth 2.0 Azure AD仅生成用于Microsoft Graph的无效访问令牌

Oauth 2.0 Azure AD仅生成用于Microsoft Graph的无效访问令牌,oauth-2.0,jwt,azure-active-directory,microsoft-graph-api,jwt-auth,Oauth 2.0,Jwt,Azure Active Directory,Microsoft Graph Api,Jwt Auth,我已在Azure Active Directory中设置应用程序注册,以便可以通过Microsoft Graph访问Microsoft OneNote笔记本/分区/页面 它允许几乎所有持有微软账户的人登录,所以我使用https://login.microsoftonline.com/common/oauth2/v2.0/authorize作为我的授权端点和https://login.microsoftonline.com/common/oauth2/v2.0/token作为我的令牌端点。 在应用

我已在Azure Active Directory中设置应用程序注册,以便可以通过Microsoft Graph访问Microsoft OneNote笔记本/分区/页面

它允许几乎所有持有微软账户的人登录,所以我使用
https://login.microsoftonline.com/common/oauth2/v2.0/authorize
作为我的授权端点和
https://login.microsoftonline.com/common/oauth2/v2.0/token
作为我的令牌端点。 在应用程序注册中,我已将API权限设置为:

  • 笔记,阅读,全部
  • 脱机访问
  • openid
  • 用户阅读
我在重定向URI中添加了一个localhost,它被列为“web”,这样我就可以按照流程进行操作

我遇到的问题是,当我最终收到我的访问令牌时,我在将其用作承载令牌时收到一个错误:

因此,按照流程,我有如下内容:

  • 通过此url进行身份验证
  • openid脱机访问

    我有点不确定这里是否使用了正确的范围变量。我希望能够访问所有用户的OneNote笔记本/分区/页面,阅读他们的个人资料,并离线执行操作

  • 当我的用户成功进行身份验证时,代码将重定向到此处:
  • http://localhost/myapp?code=M.R3_BL2.15c2b73a-486c-c0f6-95c1-8432603aa7a4和状态=abc

  • 我从querystring中提取
    代码
    ,并发布如下帖子:
  • 现在,这将返回一个JSON格式的访问令牌

    {
        "token_type": "Bearer",
        "scope": "https://graph.microsoft.com/User.Read openid https://graph.microsoft.com/Notes.Read.All",
        "expires_in": 3600,
        "ext_expires_in": 3600,
        "access_token": "EwCQA8l6BAAUO9chh8cJscQLmU+longstring",
        "refresh_token": "M.R3_BL2.CecNbvRse*longstring",
        "id_token": "eyJ0eXAiOiJKlongstring"
    }
    
    然而,如上所述,这个访问令牌似乎不允许我访问Microsoft Graph。我尝试过在请求中使用不同的作用域变体,但似乎都没有生成正确的访问令牌

    我用于从node.js调用Microsoft Graph的代码

    const http = require('https');
    
    class OneNote {
    constructor(bearer) {
            this.bearer = bearer;
            this.HTTP_CODES = {
                OK: 200,
                Unauthorized: 401
            };
        }
    
    async getNotebooks() {
            const options = this._getOptions();
            options.path += 'notebooks';
            return this._requestData(options)
                .catch((err) => {
                    throw err;
                });
        }
    
    _getOptions() {
            return {
                method: 'GET',
                hostname: 'graph.microsoft.com',
                path: '/v1.0/me/onenote/',
                headers: {
                    'Authorization': `Bearer ${this.bearer}`
                }
            }
        }
    
        async _requestData(options) {
            console.log(options)
            return new Promise((resolve, reject) => {
                const req = http.request(options, (res) => {
                    let data = '';
                    res.on('data', (d) => {
                        data += d;
                    });
                    if (res.statusCode === this.HTTP_CODES.Unauthorized) {
                        res.on('end', () => {
                            reject(data);
                        });
                    } else {
                        res.on('end', () => {
                            resolve(data);
                        });
                    }
                });
    
                req.on('error', (err) => {
                    reject(err);
                });
                req.end();
            });
        }
    }
    

    您可能使用了错误的权限(范围)

    根据,个人Microsoft帐户所需的权限为
    Notes.Create,Notes.Read,Notes.ReadWrite

    Notes.Read.此处不需要所有


    因此,请添加
    注释。请阅读范围中的
    委派权限以解决此问题。

    看起来此访问令牌正常。请分享您的呼叫请求
    https://graph.microsoft.com/v1.0/me/onenote/notebooks
    使用您的访问令牌。并解码您的访问令牌,查看其是否具有正确的
    aud
    范围
    。我可以知道您是否隐藏了真实的
    代码
    ?或者您的代码是“M.R3_BL2.15c2b73a-486c-c0f6-95c1-8432603aa7a4”?访问令牌看起来与普通令牌不同。您使用的是哪种账户?O365帐户还是Microsoft个人帐户?@AllenWu我正在使用我的个人Microsoft帐户。当我使用Microsoft Graph Explorer并将访问令牌复制到jwt.io中时,它会给出一个错误,并且不会显示任何数据,更不用说我自己生成的数据了?这是我最新的授权代码:
    M.R3_BL2.db535519-c869-054d-df35-64369bfb86fb
    。有效。。。如果我删除Notes.Read.所有这些都会阻止学校或工作用户阅读他们的笔记吗?因此,拥有这两种权限并没有什么坏处,允许个人、学校和工作账户访问其所有笔记本/分区/页面,对吗?@Jarede是的。如果您删除Notes.Read.All,则它不适用于工作帐户。但您可以在Azure AD app中同时分配
    Notes.Read
    Notes.Read.All
    委派权限并使用
    https://graph.microsoft.com/.default
    在范围内。它将允许个人、学校和工作账户。我认为没有害处。这是它的工作方式之一。
    {
        "token_type": "Bearer",
        "scope": "https://graph.microsoft.com/User.Read openid https://graph.microsoft.com/Notes.Read.All",
        "expires_in": 3600,
        "ext_expires_in": 3600,
        "access_token": "EwCQA8l6BAAUO9chh8cJscQLmU+longstring",
        "refresh_token": "M.R3_BL2.CecNbvRse*longstring",
        "id_token": "eyJ0eXAiOiJKlongstring"
    }
    
    const http = require('https');
    
    class OneNote {
    constructor(bearer) {
            this.bearer = bearer;
            this.HTTP_CODES = {
                OK: 200,
                Unauthorized: 401
            };
        }
    
    async getNotebooks() {
            const options = this._getOptions();
            options.path += 'notebooks';
            return this._requestData(options)
                .catch((err) => {
                    throw err;
                });
        }
    
    _getOptions() {
            return {
                method: 'GET',
                hostname: 'graph.microsoft.com',
                path: '/v1.0/me/onenote/',
                headers: {
                    'Authorization': `Bearer ${this.bearer}`
                }
            }
        }
    
        async _requestData(options) {
            console.log(options)
            return new Promise((resolve, reject) => {
                const req = http.request(options, (res) => {
                    let data = '';
                    res.on('data', (d) => {
                        data += d;
                    });
                    if (res.statusCode === this.HTTP_CODES.Unauthorized) {
                        res.on('end', () => {
                            reject(data);
                        });
                    } else {
                        res.on('end', () => {
                            resolve(data);
                        });
                    }
                });
    
                req.on('error', (err) => {
                    reject(err);
                });
                req.end();
            });
        }
    }