Authentication Azure AD:调用web API时出现错误401

Authentication Azure AD:调用web API时出现错误401,authentication,azure-active-directory,asp.net-core-webapi,Authentication,Azure Active Directory,Asp.net Core Webapi,我有一个简单的javascript项目(SPA应用程序),它成功地使用Azure AD对用户进行身份验证。但当我调用我的Web API时,它返回以下错误: 状况401。承载错误=“无效的\u令牌”,错误\u描述=“ “签名无效” 我的web API或SPA应用程序都没有发布在Azure AD上,但我已将它们注册为两个独立的应用程序 我已授予SPA应用程序访问管理员和用户API的权限(具有API权限) SPA应用程序javascript: function acquireTokenPopupAnd

我有一个简单的javascript项目(SPA应用程序),它成功地使用Azure AD对用户进行身份验证。但当我调用我的Web API时,它返回以下错误:

状况401。承载错误=“无效的\u令牌”,错误\u描述=“ “签名无效”

我的web API或SPA应用程序都没有发布在Azure AD上,但我已将它们注册为两个独立的应用程序

我已授予SPA应用程序访问管理员和用户API的权限(具有API权限)

SPA应用程序javascript:

function acquireTokenPopupAndCallMSGraph() {
    //Always start with acquireTokenSilent to obtain a token in the signed in user from cache
    myMSALObj.acquireTokenSilent(requestObj).then(function (tokenResponse) {
        MyAccessToken = tokenResponse.accessToken;   

        callMSGraph(graphConfig.graphMeEndpoint, tokenResponse.accessToken, graphAPICallback);

        // Call the API - my code.            
        var accessToken = tokenResponse.accessToken;           
        var apiUrl = "https://localhost:44353/api/values";                       
        callAPI(apiUrl, accessToken, APICallback);


    }).catch(function (error) {
        console.log(error);
        // Upon acquireTokenSilent failure (due to consent or interaction or login required ONLY)
        // Call acquireTokenPopup(popup window) 
        if (requiresInteraction(error.errorCode)) {
            myMSALObj.acquireTokenPopup(requestObj).then(function (tokenResponse) {
                callMSGraph(graphConfig.graphMeEndpoint, tokenResponse.accessToken, graphAPICallback);
            }).catch(function (error) {
                console.log(error);
            });
        }
    });
}

function callMSGraph(theUrl, accessToken, callback) {
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200)
            callback(JSON.parse(this.responseText));
    }
    xmlHttp.open("GET", theUrl, true); // true for asynchronous
    xmlHttp.setRequestHeader('Authorization', 'Bearer ' + accessToken);
    xmlHttp.send();
}

function callAPI(theUrl, accessToken, callback) {
    console.log("Calling the API.");
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200)
            callback(JSON.parse(this.responseText));
    }
    xmlHttp.open("GET", theUrl, true); // true for asynchronous
    xmlHttp.setRequestHeader('Authorization', 'Bearer ' + accessToken);
    xmlHttp.send();
}
javascript代码来自以下Azure广告示例代码:

startup.cs(web API)

appsettings.json(web API)

值控制器.cs

 [Authorize]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { "value1", "value2" };
    }
[授权]
[路由(“api/[控制器]”)]
[ApiController]
公共类值控制器:控制器库
{
//获取api/值
[HttpGet]
公共行动结果获取()
{
返回新字符串[]{“value1”,“value2”};
}

问题:为什么我需要不同的API访问令牌

回答:Azure AD不允许用户对多个Azure AD资源使用相同的访问令牌。如果您想访问多个Azure AD资源,可以使用刷新令牌获取多个资源的多个访问令牌。有关详细信息,请参阅

方法:Post
网址:https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
标题:
内容类型:application/x-www-form-urlencoded
正文:
客户识别码=
范围=
刷新令牌=OAAABAAAIL9KN2Z27UUBVWFPBM0GLWQJVZCTE9UKP3PSX1AXXUJQ。。。
授予\类型=刷新\令牌
客户端密码=

前端的代码有点小(
requestObj
未解释)。但据我所知,你在graph API和你的API中都使用了相同的访问令牌。这不起作用。你需要为你的API获取一个专门的令牌。谢谢你的评论!我使用了Azure的javascript快速入门示例代码,你可以在这里看到:但是,有一个问题,为什么我需要为AP使用不同的访问令牌我?我设法在react adal库的另一个示例代码中使用了相同的令牌。因为访问令牌始终只能用于一个API。您好,感谢您的评论。我已经考虑了您的答案,但没有时间对其进行适当研究。在我的应用程序中使用一个访问和ID令牌是有效的。我从Azure AD获取它并将其发送给我的管理员llers对用户进行身份验证。您好。我认为您不能使用一个访问令牌来获取不同的资源。这似乎对我有效。我已在我的公司Azure AD上注册了我的本地web应用程序,并请求访问和ID令牌。然后我将带有HTTP头的访问令牌从我的前端发送到我的web控制器(react)。后端似乎可以识别用户是否经过身份验证。根据您提供的代码,您希望调用Graph API和您开发的API。它们受Azure AD保护。但是一个访问令牌只能用于调用Graph或您开发的API。因为它们具有不同的作用域。您是对的,我想调用Graph API(以获取有关用户角色及其组的信息)。将尝试使用令牌调用它。关于API,我只是在azure上注册为API的web应用程序控制器(后端)。
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "ClientId": "[My API application ID]",
    "Domain": "[mycompany.com]",
    "TenantId": "[my tenant ID]"
  },
 [Authorize]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { "value1", "value2" };
    }
Method : Post
URL: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Header:
       Content-Type: application/x-www-form-urlencoded
Body:
    client_id=<your app id>
    scope=<>
    refresh_token=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq...
    grant_type=refresh_token
    client_secret=<your secret>