asp.net-core - 如何在 Identity Server 4 中验证 AAD 用户?
问题描述
我已将 Identity Server 4 中的 Azure Active Directory 集成为外部提供程序。
我想使用 API 从 Identity Server 4 对 Azure Active Directory 用户进行身份验证。
这是代码:
var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001");
if (disco.IsError)
{
Console.WriteLine(disco.Error);
return;
}
// request token
var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = "client",
ClientSecret = "secret",
Scope = "api1",
UserName = "ad user name",
Password = "add user password"
});
当我执行这段代码时,我收到了无效的用户名或密码错误。
注意:提供的凭据是有效的。
这是我的 startup.cs 文件
using IdentityServer4;
using IdentityServer4.EntityFramework.DbContexts;
using IdentityServer4.EntityFramework.Mappers;
using MorpheusIdentityServer.Quickstart.UI;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using IdentityServer4.Validation;
namespace MorpheusIdentityServer
{
public class Startup
{
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
string connectionString = Configuration.GetSection("ConnectionString").Value;
var builder = services.AddIdentityServer()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddProfileService<ProfileService>();
services.AddAuthentication()
.AddOpenIdConnect("aad", "Azure AD", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.Authority = Configuration.GetSection("ActiveDirectoryAuthority").Value;
options.ClientId = Configuration.GetSection("ActiveDirectoryClientId").Value;
options.ResponseType = OpenIdConnectResponseType.IdToken;
options.CallbackPath = "/signin-aad";
options.SignedOutCallbackPath = "/signout-callback-aad";
options.RemoteSignOutPath = "/signout-aad";
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role",
ValidateIssuer = false
};
});
services.AddSingleton<IResourceOwnerPasswordValidator, ValidateExternalUser>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
InitializeDatabase(app);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
private void InitializeDatabase(IApplicationBuilder app)
{
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
context.Database.Migrate();
if (!context.Clients.Any())
{
foreach (var client in Config.Clients)
{
context.Clients.Add(client.ToEntity());
}
context.SaveChanges();
}
if (!context.IdentityResources.Any())
{
foreach (var resource in Config.IdentityResources)
{
context.IdentityResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
if (!context.ApiScopes.Any())
{
foreach (var resource in Config.ApiScopes)
{
context.ApiScopes.Add(resource.ToEntity());
}
context.SaveChanges();
}
}
}
}
}
解决方案
我已经搜索并找到了一些可能的方法来自定义外部提供商的用户名和密码。以下是步骤
1-实现如下所示的类
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
public Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
var username= context.UserName;
var password= context.Password;
// write the code which will validate the username and password from external provider.
}
}
2- 然后在 startup.cs 文件中注册这个接口,如下所示:
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
因此,当您尝试调用端点 /connect/token 时,将触发此类。
推荐阅读
- python - 如何更改 django admin 更改列表页面选项卡的标题
- javascript - 如果 Map 中的条件 // React JS
- swift - swift combine sink receiveValue 内存泄漏
- css - 将 CSS 与 SVG 结合使用
- c# - 将输入字段中的一个值分配给 Razor 中的两个模型对象
- python - 从 python 脚本调用 ExifTool 在 Mac 中挂起,但在 Windows 中有效
- javascript - 画布javascript drawImage方法
- javascript - PM2 错误 - 错误:错误:spawn wmic ENONET
- ios - RxSwift Observable 不发出值
- callback - 在散景回调中使用自定义 js 创建 .xlsx