使用Curl访问由Microsoft身份平台(Azure Ad)保护的API

我们有一个.net核心应用程序,该应用程序使用Azure AD进行身份验证(MSAL / v2.0)。我们希望linux应用程序从第一个应用程序访问API。第二个应用程序没有用户上下文,将完全与curl脚本进行交互。

通过阅读文档,我相信我应该使用Azure广告注册第二个应用程序。我可以得到一个JWT令牌,该令牌具有目标应用程序作为访问者,但是我无法访问api。我们已经能够使用从登录用户获取的访问令牌从脚本访问(真实)api。

我创建了一个Test环境来查找解决方案。

创建了一个通过Azure广告进行身份验证的.net核心项目。它是从我的工作站本地运行的,尚未部署到Azure。 Azure身份验证适用于交互式用户。

注册了第二个应用程序,并为其创建了一个秘密。

第一个应用程序同时配置了ID和访问令牌以进行隐式授予,未将其设置为公共客户端。

我在清单中定义了一个方法“ access_as_application”。

在公开API下,我创建了一个范围“ api”,并将另一个应用程序添加为授权的客户端应用程序。

在API权限下,我添加了权限,选择了应用程序权限,并检查了我之前创建的方法。

我可以运行curl脚本并检索承载令牌,该令牌在解码时会显示与我的应用程序匹配的受众。当我在curl脚本中使用该令牌时,它将被重定向以登录。

清单:

{
    "id": "33b*******************************","acceptMappedClaims": null,"accessTokenacceptedVersion": 2,"addIns": [],"allowPublicClient": null,"appId": "3d8*******************************","appRoles": [
        {
            "allowedMemberTypes": [
                "Application"
            ],"description": "access webapp as an application.","displayName": "access_as_application","id": "ff5ea9b2*******************************",","isEnabled": true,"lang": null,"origin": "Application","value": "access_as_application"
        }
    ],"oauth2AllowUrlPathMatching": false,"createdDateTime": "2019-10-29T16:49:37Z","groupmembershipClaims": null,"identifierUris": [
        "api://3d8*******************************"
    ],"informationalUrls": {
        "termsOfService": null,"support": null,"privacy": null,"marketing": null
    },"keyCredentials": [],"knownClientApplications": [],"logoUrl": null,"logoutUrl": "https://localhost:44321/signout-callback-oidc","name": "WebApp","oauth2AllowIdTokenImplicitFlow": true,"oauth2AllowImplicitFlow": true,"oauth2Permissions": [
        {
            "adminConsentDescription": "consent for api","adminConsentDisplayName": "consent for api","id": "a4b2*******************************","type": "Admin","userConsentDescription": null,"userConsentDisplayName": null,"value": "api"
        }
    ],"oauth2RequirePostResponse": false,"optionalClaims": null,"orgRestrictions": [],"parentalControlSettings": {
        "countriesBlockedForMinors": [],"legalAgeGroupRule": "Allow"
    },"passwordCredentials": [
        {
            "customKeyIdentifier": null,"endDate": "2299-12-31T05:00:00Z","keyId": "e03c4*******************************","startDate": "2019-10-31T20:05:42.56Z","value": null,"createdOn": "2019-10-31T20:05:42.7555795Z","hint": "00_","displayName": "webappsecret"
        }
    ],"preAuthorizedApplications": [
        {
            "appId": "a4b*******************************","permissionIds": [
                "23b*******************************"
            ]
        },{
            "appId": "3d8*******************************","permissionIds": [
                "23b*******************************"
            ]
        }
    ],"publisherDomain": "brainbuzgmail.onmicrosoft.com","replyUrlsWithType": [
        {
            "url": "https://localhost:44321/signin-oidc","type": "Web"
        },{
            "url": "https://localhost:44321/","type": "Web"
        }
    ],"requiredResourceaccess": [
        {
            "resourceAppId": "3d8*******************************","resourceaccess": [
                {
                    "id": "23b*******************************","type": "Scope"
                },{
                    "id": "ff5ea*******************************","type": "Role"
                }
            ]
        },{
            "resourceAppId": "a4b*******************************","resourceaccess": [
                {
                    "id": "a37a*******************************",{
                    "id": "ccf78*******************************",{
            "resourceAppId": "00000003-0000-0000-c000-000000000000","resourceaccess": [
                {
                    "id": "e1fe*******************************","type": "Scope"
                }
            ]
        }
    ],"samlMetadataUrl": null,"signInUrl": null,"signInAudience": "AzureADmyorg","tags": [],"tokenEncryptionKeyId": null
}

变量$在环境中设置。从成功的请求中捕获令牌,并将其设置为$ TOKEN。由于本地应用使用了自签名证书,因此-k insecure标志在curl中使用。

curl -X POST -d "grant_type=client_credentials&client_id=$CLIENTID&client_secret=$SECRET&resource=$SCOPE" https://login.microsoftonline.com/$TENANT/oauth2/token

curl -k 'https://localhost:44321/api/' \
-H 'accept: application/json' \
-H "Authorization: Bearer $TOKEN" \
-H 'Sec-Fetch-Mode: cors' -H 'Content-Type: application/json' --compressed

部分响应重定向到登录页面,即使它具有有效的访问令牌,也似乎要求客户端获取ID令牌:

< HTTP/2 302
< location: https://login.microsoftonline.com/****/oauth2/v2.0/authorize?client_id=***&redirect_uri=https%3A%2F%2Flocalhost%3A44321%2Fsignin-oidc&response_type=id_token
kingking0112 回答:使用Curl访问由Microsoft身份平台(Azure Ad)保护的API

如果您只希望Linux应用程序调用受Azure AD保护的.net核心应用程序的API,则这是一个service to service call flow,并且无需像通常这样重定向到/authorize终结点端点是用户登录的步骤之一。

根据您的描述,您已成功获取访问令牌,并且可以将此令牌用作API请求中的授权承载标头,以直接调用.net核心应用程序。

TodoListService的{​​{3}}主题是一个示例API边演示,将对您有所帮助。在您的情况下,您应该进行一些修改以使服务能够在服务调用中起作用。

1。用以下代码替换Controllers/TodoListController.csTodoListService的内容:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web.Resource;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using TodoListService.Models;

namespace TodoListService.Controllers
{
    [Authorize]
    [Route("api/[controller]")]
    public class TodoListController : Controller
    {
        static readonly ConcurrentBag<TodoItem> TodoStore = new ConcurrentBag<TodoItem>();

        /// <summary>
        /// The Web API will only accept tokens 1) for users,and 
        /// 2) having the access_as_user scope for this API
        /// </summary>
        static readonly string[] scopeRequiredByApi = new string[] { "access_as_application" };

        // GET: api/values
        [HttpGet]
        public IEnumerable<TodoItem> Get()
        {
         //   HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
            string owner = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            return TodoStore.Where(t => t.Owner == owner).ToList();
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody]TodoItem todo)
        {
            //check roles claim in token start
            Claim scopeClaim = HttpContext.User?.FindFirst("http://schemas.microsoft.com/ws/2008/06/identity/claims/role");
            if (scopeClaim == null || !scopeClaim.Value.Split(' ').Intersect(scopeRequiredByApi).Any())
            {
                HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                string message = $"The 'roles' claim does not contain scopes '{string.Join(",",scopeRequiredByApi)}' or was not found";
                throw new HttpRequestException(message);
            }
            //check roles claim end
            string owner = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            TodoStore.Add(new TodoItem { Owner = owner,Title = "test!!" });
        }
    }
}

this demo

  1. WebApiServiceCollectionExtensions.cs项目的Microsoft.Identity.Web的第80行中,用下面的代码替换以确保将检查您的角色声明:

    &&!context.Principal.Claims.Any(y => y.Type ==“ enter image description here”))

http://schemas.microsoft.com/ws/2008/06/identity/claims/role

在这里进行测试,发布请求: enter image description here

获取记录: enter image description here

希望有帮助。

本文链接:https://www.f2er.com/3113800.html

大家都在问