我正在尝试创建 REST 端点,用于在 Azure Entra (AD) 中创建用户并验证用户是否存在于组中。这些端点将从自定义前端应用程序调用。
我尝试了以下代码,但不幸的是,我遇到了以下错误:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Graph;
using Microsoft.Graph.Models;
using Microsoft.Identity.Client;
using Azure.Identity;
// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace Entra_SPIKE.Controllers
{
[ApiController]
[Route("[controller]")]
public class CreateUserController : Controller
{
private GraphServiceClient _graphServiceClient;
public CreateUserController(GraphServiceClient graphServiceClient)
{
_graphServiceClient = graphServiceClient;
}
[HttpPost(Name = "PostCreateUser")]
public async Task<IActionResult> CreateUser([FromBody] CreateUserRequest request)
{
try
{
var user = new User
{
AccountEnabled = request.AccountEnabled,
DisplayName = request.DisplayName,
MailNickname = request.MailNickname,
UserPrincipalName = request.UserPrincipalName ,
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = request.ForceChangePasswordNextSignIn,
Password = request.Password
}
};
// The client credentials flow requires that you request the
// /.default scope, and pre-configure your permissions on the
// app registration in Azure. An administrator must grant consent
// to those permissions beforehand.
var scopes = new[] { "https://graph.microsoft.com/.default" };
// Values from app registration
var tenantId = "MY-ID";
// Values from app registration
var clientId = "MY-ID";
var clientSecret = "MY-Password";
// using Azure.Identity;
var options = new ClientSecretCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
};
// https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
var graphclient = new GraphServiceClient(clientSecretCredential, scopes);
var result = await graphclient.Users.PostAsync(user);
return Ok("User created successfully");
}
catch (Exception ex)
{
return StatusCode(500, $"An error occurred: {ex.Message}");
}
}
}
public class CreateUserRequest
{
public string DisplayName { get; set; }
public string MailNickname { get; set; }
public string UserPrincipalName { get; set; }
public string Password { get; set; }
public bool AccountEnabled { get; set; }
public bool ForceChangePasswordNextSignIn { get; set; }
}
}
System.InvalidOperationException:无法解析类型的服务 尝试激活时出现“Microsoft.Graph.GraphServiceClient” 'Entra_SPIKE.Controllers.CreateUserController'。在 Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp,类型 type,类型 requiredBy,布尔值 isDefaultParameterRequired)
...
有人可以指导我吗?
首先,Azure AD 提供了多种身份验证流程,客户端凭据流程用于 Daemon 应用程序,该应用程序没有 UI 来让用户登录以获取身份验证,Daemon 应用程序只能代表应用程序进行身份验证本身。而如果应用程序是具有 UI 的 SPA 或 MVC 应用程序,以便它可以让用户登录,那么身份验证代码流可能是另一种选择,以便应用程序可以帮助代表用户进行身份验证。
回到您的场景,您有一个 API 项目,并且在控制器方法中您想通过 Graph SDK 调用 Graph API,因此您必须对
GraphServiceClient
进行身份验证。
通过 DI 使用
_graphServiceClient
始终用于身份验证代码流,通常与 builder.Services.AddRazorPages().AddMicrosoftIdentityUI();
和 builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme).AddMicrosoftIdentityWebApp(builder.Configuration).EnableTokenAcquisitionToCallDownstreamApi(initialScopes).AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi")).AddInMemoryTokenCaches();
一起使用。这需要用户登录。
但是Web API无法让用户登录,因此我们还有另一个选择,使用代表流程,这样我们仍然可以代表用户对GraphServiceClient进行身份验证。我们可以使用
builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration).EnableTokenAcquisitionToCallDownstreamApi().AddMicrosoftGraph(builder.Configuration.GetSection("Graph")).AddInMemoryTokenCaches();
来代替。
如果我们不需要代表用户对 GraphServiceClient 进行身份验证,那么就像您已经拥有的用于客户端凭据流的
var graphclient = new GraphServiceClient(clientSecretCredential, scopes);
一样,那么不需要依赖项注入,只需注释它们即可避免异常。顺便说一句,异常总是来自于没有 builder.service.xxx.AddMicrosoftGraph
。如果您添加该部分但没有用户登录信息,则会引发另一个异常。
我之前在Web api项目中使用On-behalf-of flow进行了测试,如果需要,您可以检查一下。该示例使用了 Graph SDK v4.x。