在 ASP.NET Core 中使用两个 AD 进行自定义身份验证
Custom authentication with two ADs in ASP.NET Core
我有一个 ASP.NET Core 5 应用程序,它在 Windows 服务器上使用身份框架。当用户在登录页面点击提交时,需要
- 根据 AD #1 验证他们的用户名和密码。
- 如果失败,则需要根据 AD #2 对它们进行身份验证。
- 如果同样失败,它应该给出一个错误。
这个 post 涵盖了 AD 身份验证,但我不知道它应该去哪里或如何触发:
此答案提供了有关创建自定义身份验证的详细信息,但如何将其集成到已有 UserManager
的身份框架中?
如果我只想通过身份验证锁定应用程序,我是否需要身份库?有更简单的方法吗?
谢谢。
更新: 请参阅下面的 RazorPages 答案。类似的逻辑可以用于 MVC 版本。
要使其与 RazorPages 一起使用,我们需要在 Startup.cs
中添加以下内容:
public void ConfigureServices(IServiceCollection services)
{
// Other statements...
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(x => x.LoginPath = "/login");
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Other statements...
app.UseAuthentication();
app.UseAuthorization();
}
然后在 PageModel
我们要验证的页面上,我们将 [Authorize] 属性添加到 class.
然后在 LoginModel
PageModel 中:
public class LoginModel : PageModel
{
[BindProperty]
[DisplayName("Username:")]
[Required]
public string Username { get; set; }
[BindProperty]
[Required]
[DataType(DataType.Password)]
[DisplayName("Password:")]
public string Password { get; set; }
public string ReturnUrl { get; set; }
public void OnGet(string returnUrl = null)
{
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
if (!ModelState.IsValid)
{
return Page();
}
// Check both LDAPs. User must authenticate against one
var isAuthenticated = IsAuthenticated(ConfigurationManager.AppSettings["MyFirstLDAPPath"]) || IsAuthenticated(ConfigurationManager.AppSettings["MySecondLDAPPath"]);
if (isAuthenticated)
{
// Must provide at least the Username claim or it will throw an InvalidOperationException
var identity = new ClaimsIdentity(new List<Claim>{ new Claim(ClaimTypes.Name, Username, ClaimValueTypes.String, "SomeUniqueValue") }, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal,
new AuthenticationProperties());
return LocalRedirect(returnUrl);
}
ViewData["Message"] = "Invalid credentials.";
ReturnUrl = returnUrl;
return Page();
}
// This is a reliable way to check the user's credentials.
// Note that this also considers users with a changed password,
// as some other techniques don't
private bool IsAuthenticated(string ldapPath)
{
try
{
var conn = new LdapConnection(ldapPath);
conn.Credential = new NetworkCredential(Username, Password);
conn.Bind();
return true;
}
catch (Exception)
{
return false;
}
}
}
然后在Login.cshtml
:
<form asp-route-returnurl="@returnUrl" method="post">
@Html.AntiForgeryToken()
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
@if (!string.IsNullOrEmpty(ViewData["Message"]?.ToString()))
{
<span class="text-danger">
@ViewData["Message"]
</span>
}
@Html.HiddenFor(x => x.ReturnUrl)
<h3 class="text-center text-info">Login</h3>
<div class="form-group">
<label asp-for="Username" class="text-info"></label>
<input asp-for="Username" class="form-control" autofocus/>
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password" class="text-info"></label>
<input asp-for="Password" class="form-control"/>
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" name="submit" class="btn btn-info btn-md" value="submit">
</div>
</form>
希望这对其他人有帮助。
我有一个 ASP.NET Core 5 应用程序,它在 Windows 服务器上使用身份框架。当用户在登录页面点击提交时,需要
- 根据 AD #1 验证他们的用户名和密码。
- 如果失败,则需要根据 AD #2 对它们进行身份验证。
- 如果同样失败,它应该给出一个错误。
这个 post 涵盖了 AD 身份验证,但我不知道它应该去哪里或如何触发:
此答案提供了有关创建自定义身份验证的详细信息,但如何将其集成到已有 UserManager
的身份框架中?
如果我只想通过身份验证锁定应用程序,我是否需要身份库?有更简单的方法吗?
谢谢。
更新: 请参阅下面的 RazorPages 答案。类似的逻辑可以用于 MVC 版本。
要使其与 RazorPages 一起使用,我们需要在 Startup.cs
中添加以下内容:
public void ConfigureServices(IServiceCollection services)
{
// Other statements...
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(x => x.LoginPath = "/login");
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Other statements...
app.UseAuthentication();
app.UseAuthorization();
}
然后在 PageModel
我们要验证的页面上,我们将 [Authorize] 属性添加到 class.
然后在 LoginModel
PageModel 中:
public class LoginModel : PageModel
{
[BindProperty]
[DisplayName("Username:")]
[Required]
public string Username { get; set; }
[BindProperty]
[Required]
[DataType(DataType.Password)]
[DisplayName("Password:")]
public string Password { get; set; }
public string ReturnUrl { get; set; }
public void OnGet(string returnUrl = null)
{
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
if (!ModelState.IsValid)
{
return Page();
}
// Check both LDAPs. User must authenticate against one
var isAuthenticated = IsAuthenticated(ConfigurationManager.AppSettings["MyFirstLDAPPath"]) || IsAuthenticated(ConfigurationManager.AppSettings["MySecondLDAPPath"]);
if (isAuthenticated)
{
// Must provide at least the Username claim or it will throw an InvalidOperationException
var identity = new ClaimsIdentity(new List<Claim>{ new Claim(ClaimTypes.Name, Username, ClaimValueTypes.String, "SomeUniqueValue") }, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal,
new AuthenticationProperties());
return LocalRedirect(returnUrl);
}
ViewData["Message"] = "Invalid credentials.";
ReturnUrl = returnUrl;
return Page();
}
// This is a reliable way to check the user's credentials.
// Note that this also considers users with a changed password,
// as some other techniques don't
private bool IsAuthenticated(string ldapPath)
{
try
{
var conn = new LdapConnection(ldapPath);
conn.Credential = new NetworkCredential(Username, Password);
conn.Bind();
return true;
}
catch (Exception)
{
return false;
}
}
}
然后在Login.cshtml
:
<form asp-route-returnurl="@returnUrl" method="post">
@Html.AntiForgeryToken()
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
@if (!string.IsNullOrEmpty(ViewData["Message"]?.ToString()))
{
<span class="text-danger">
@ViewData["Message"]
</span>
}
@Html.HiddenFor(x => x.ReturnUrl)
<h3 class="text-center text-info">Login</h3>
<div class="form-group">
<label asp-for="Username" class="text-info"></label>
<input asp-for="Username" class="form-control" autofocus/>
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password" class="text-info"></label>
<input asp-for="Password" class="form-control"/>
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" name="submit" class="btn btn-info btn-md" value="submit">
</div>
</form>
希望这对其他人有帮助。