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