如何在我的.NET API中使用Azure AD登录?

huangapple go评论149阅读模式
英文:

How can I use an Azure AD login for my .NET API?

问题

我有一个.NET 7 API,要求用户必须拥有Microsoft账户。为了让顾客更容易登录,我希望他们能够使用他们的Microsoft账户登录。目标受众是经常阻止他们的用户授予权限给新应用程序的大型组织。我发现实现这一目标的最简单方式是只使用Microsoft Graph API的"email"权限来登录用户。

我将简要解释当前的设置:

  • 我在我们的Azure AD中注册了一个名为"MyApi"的AD应用程序。它对所有组织都是开放的,只有一个权限:"email"(来自Microsoft Graph API)。
  • 我在我的前端Web应用程序中添加了一个按钮,将用户发送到https://login.microsoftonline.com/common/oauth2/authorize?client_id=[MyApi.ClientId]&redirect_uri=[MyApi.RedirectUri]&response_type=code&prompt=consent&scope=offline_access&response_mode=query
  • 然后,我使用https://login.microsoftonline.com/common/oauth2/token端点以scope = "offline_access"交换代码以获取令牌。
  • 然后,我收到一个令牌,其受众为00000002-0000-0000-c000-000000000000(这是Microsoft Graph API),appId为MyApi.ClientId
  • 在启动类中,我做了以下操作:
IConfigurationSection azureAdSection = _configuration.GetSection("AzureAd");
azureAdSection.GetSection("Instance").Value = "https://login.microsoftonline.com/";
azureAdSection.GetSection("Audience").Value = "00000002-0000-0000-c000-000000000000";
azureAdSection.GetSection("ClientId").Value = MyApi.ClientId;
azureAdSection.GetSection("ClientSecret").Value = MyApi.ClientSecret;
azureAdSection.GetSection("TenantId").Value = "organizations";
services.AddMicrosoftIdentityWebApiAuthentication(_configuration, "AzureAd");

我首先尝试了使用第二个Azure AD应用程序,该应用程序具有已公开的权限,然后我在MyApi应用程序中使用它。但这导致了Azure AD错误,例如:

AADSTS650052: 该应用程序试图访问您的组织[My TenantID]缺少服务主体的服务MySecondApp.ClientId。
请联系您的IT管理员,以审查您的服务订阅或同意应用程序以创建所需的服务主体的配置。

然后,我们得出结论,我们可能根本不需要这个第二个应用程序。

在当前的设置中,似乎一切都运作正常,但这是否是正确的方式?

通过这样做,我获得了一个令牌,可以保证用户是Microsoft用户(这是可靠的),我可以看到他们的电子邮件和ID是什么。这些数据将允许我在我们的数据库中找到匹配的用户并返回所请求的响应。我不需要自定义范围,因为所有授权和权限都由API本身处理。

在其他帖子和文档中,通常需要自定义范围或使用令牌调用下游API(通常是Graph API本身),而这里都是不需要的。

英文:

I have a .NET 7 API that requires the user to have a Microsoft account. So to make it easier for the customer I want them to be able to login with their Microsoft account. The target audience is big organizations that often block their users from giving permissions to new apps. The simplest way I found to do this was to simply log the user in with only the "email" permission of the Microsoft Graph API.

I will briefly explain the current setup:

IConfigurationSection azureAdSection = _configuration.GetSection("AzureAd");
azureAdSection.GetSection("Instance").Value = "https://login.microsoftonline.com/";
azureAdSection.GetSection("Audience").Value = "00000002-0000-0000-c000-000000000000";
azureAdSection.GetSection("ClientId").Value = MyApi.ClientId;
azureAdSection.GetSection("ClientSecret").Value = MyApi.ClientSecret;
azureAdSection.GetSection("TenantId").Value = "organizations";
services.AddMicrosoftIdentityWebApiAuthentication(_configuration, "AzureAd");

I first tried it with a second Azure AD App that had exposed permission which I then used in the MyApi app. But this caused Azure AD Errors like this one:

AADSTS650052: The app is trying to access a service MySecondApp.ClientId that your organization [My TenantID]
lacks a service principal for.
Contact your IT Admin to review the configuration of your service subscriptions or consent
to the application in order to create the required service principal.

We then came to the conclusion that we probably don't even need this second app.

With the current setup everything seems to work fine, but is it the correct way?

By doing this I have a token that guarantees me that the user is a Microsoft user (which is reliable) and I can see what their email and id is. This data will allow me to find the matching user in our database and return the requested response. I have no need for custom scopes as all authorization and permissions are handled by the API itself.

In other posts and documentation there is a need for custom scopes or for using the token to call a downstream API (often the Graph API itself), all which isn't needed here.

答案1

得分: 1

你现在拥有一个.NET 7 Web API,并且在你的启动文件中有 services.AddMicrosoftIdentityWebApiAuthentication(_configuration, "AzureAd");,因此你现在正在使用 Azure AD 保护你的 API。这个保护意味着当请求到达你的 API 时,它必须在请求头中包含一个正确的 Bearer access_token。这里的 "正确" 意味着它应该具有正确的受众、客户端 ID、范围/角色,以及必须是有效/未过期等。

所以你必须拥有一个 Azure AD 应用程序(你已经拥有它),并公开一个 API,然后你可以将此 API 权限分配给此应用程序(这样你就不必创建另一个 AAD 应用程序)。然后在你的前端应用程序中,你需要通过这个 AAD 应用程序生成访问令牌,并设置范围的值,该值应该类似于 api://client_id/permission_name。然后令牌应该具有 "aud": "api://client_id","scp": "permission_name",。并且这个令牌应该能够绕过你的 Web API 的验证。

在你的 API 权限中,你应该有如下的代码和配置:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

"AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "ClientId": "aad_client_id",
    "ClientSecret": "client_secret",
    "TenantId": "organizations", // 一个 GUID(租户 ID = 目录 ID)或 'common' 或 'organizations' 或 'consumers'
    "Audience": "api://aad_client_id"
},

要生成这种类型的访问令牌,你必须先让用户使用 MSAL 登录。如果你的客户端应用程序是用 React 编写的,也许你可以看一下这个答案。请注意,你需要将范围设置为 api://client_id/permission_name,以生成包含此范围的令牌。

英文:

What you have is an .Net 7 webapi, and you had services.AddMicrosoftIdentityWebApiAuthentication(_configuration, "AzureAd"); in your startup file, so you are now using Azure AD to protect your API. This protect means when a request reaching your API, it must contain a correct Bearer access_token in the request header. Here the correct means it should have correct audience, client id, scope/role, and it must be valid/not expired, etc.

So you have to have an Azure AD application(you already have it) and expose an API, then you can assign this API permission to this application(so that you don't have to create another AAD app). Then in your frontend application, you need to generate access token via this AAD app and setting the scope with the value you exposed just now, the value should looks like api://client_id/permission_name. Then the token should have "aud": "api://client_id", and have "scp": "permission_name",. And this token should be able to bypass the validation of your web API.

In your API permission, you should have code and configurations like this:

    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "ClientId": "aad_client_id",
    "ClientSecret": "client_secret",
    "TenantId": "organizations", // A guid (Tenant ID = Directory ID) or 'common' or 'organizations' or 'consumers'
    "Audience": "api://aad_client_id"
  },

To generate such kind of access token, you have to let user sign in first with MSAL. If your client app is written in react, maybe you can take a look at this answer. Please note you need to set the scope to api://client_id/permission_name to generate a token containing this scope.

huangapple
  • 本文由 发表于 2023年6月5日 15:26:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76404281.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定