ASP.NET MVC和混合模式身份验证
-
19-09-2019 - |
题
我有一种情况,其中我需要用户能够对使用Windows身份验证或窗体身份验证的ASP.NET MVC的Web应用程序进行身份验证。如果用户是在内部网络上,他们将使用Windows身份验证,如果它们被连接在外部,他们将使用Forms身份验证。我见过不少人问的问题我该如何配置这一个ASP.NET MVC的Web应用程序,但我还没有找到一个完整的解释。
请有人可以提供详细的解释,有代码实例,如何做到这一点呢?
感谢。
艾伦Ť
解决方案
此被称为混合身份验证模式。基本上你不能一个的单的应用程序中,因为在IIS一旦您设置Windows身份验证的虚拟目录,将不再接受来自不同域的用户实现这一目标。所以基本上你需要有使用窗体身份验证两个应用程序,先用Windows身份验证和第二(主应用程序)。所述第一应用将包括这将简单地通过发出认证券域用户重定向到主应用程序的单个地址的
其他提示
这可以做到的。反向配置,设置应用程序/根使用匿名和窗体身份验证......就这样,你可以在同一个Web应用程序中配置混合身份验证,但它是棘手的。因此,首先,配置你的应用程序与loginUrl =“〜/ WinLogin / WinLogin2.aspx”窗体身份验证。在MVC中,路由覆盖由IIS设置身份验证规则,因此需要使用一个aspx页面,如IIS可以在文件上设置身份验证。在根上启用Web应用程序的匿名和窗体身份验证。启用Windows身份验证和根/ WinLogin目录禁用匿名身份验证。添加自定义401和401.2错误页面重定向回帐户/登入网址。
这将允许能够贯通的使用集成验证自动登入窗口的任何浏览器。虽然一些设备将得到提示凭据(如iPhone)和其他设备,如黑莓重定向到登录页面。
这也创造了一个cookie明确添加用户的角色,并创建一个通用的原则,所以可以使用基于角色的授权。
在WinLogin2.aspx(下IIS中的“根”的Web应用程序WinLogin目录,并配置为使用Windows身份验证,匿名禁用,并启用表单(如无法关闭......注意IIS会当您启用抱怨窗口验证,只是忽略):
var logonUser = Request.ServerVariables["LOGON_USER"];
if (!String.IsNullOrWhiteSpace(logonUser))
{
if (logonUser.Split('\\').Length > 1)
{
var domain = logonUser.Split('\\')[0];
var username = logonUser.Split('\\')[1];
var timeout = 30;
var encTicket = CreateTicketWithSecurityGroups(false, username, domain, timeout);
var authCookie = new HttpCookie(".MVCAUTH", encTicket) { HttpOnly = true };
Response.Cookies.Add(authCookie);
}
//else
//{
// this is a redirect due to returnUrl being WinLogin page, in which logonUser will no longer have domain attached
// ignore as forms ticket should already exist
//}
string returnUrl = Request.QueryString["ReturnUrl"];
if (returnUrl.IsEmpty())
{
Response.Redirect("~/");
}
else
{
Response.Redirect(returnUrl);
}
}
public static string CreateTicketWithSecurityGroups(bool rememberMe, string username, string domain, int timeout)
{
using (var context = new PrincipalContext(ContextType.Domain, domain))
{
using (var principal = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username))
{
var securityGroups = String.Join(";", principal.GetAuthorizationGroups());
var ticket =
new FormsAuthenticationTicket(1,
username,
DateTime.UtcNow,
DateTime.UtcNow.AddMinutes(timeout),
rememberMe,
securityGroups,
"/");
string encTicket = FormsAuthentication.Encrypt(ticket);
return encTicket;
}
}
}
在IIS 7.5,单击错误页,设置401页到文件Redirect401.htm文件的路径,在该代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org /TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script>
window.location.assign('../Account/Signin');
</script>
</head>
<body>
</body>
</html>
在的AccountController ...
public ActionResult SignIn()
{
return View(new SignInModel());
}
//
// POST: /Account/SignIn
[HttpPost]
public ActionResult SignIn(SignInModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
string encTicket = CreateTicketWithSecurityGroups(model.RememberMe, model.UserName, model.Domain, FormsAuthentication.Timeout.Minutes);
Response.Cookies.Add(new HttpCookie(".MVCAUTH", encTicket));
//var returnUrl = "";
for (var i = 0; i < Request.Cookies.Count; i++)
{
HttpCookie cookie = Request.Cookies[i];
if (cookie.Name == ".MVCRETURNURL")
{
returnUrl = cookie.Value;
break;
}
}
if (returnUrl.IsEmpty())
{
return Redirect("~/");
}
return Redirect(returnUrl);
}
ModelState.AddModelError("Log In Failure", "The username/password combination is invalid");
}
return View(model);
}
//
// GET: /Account/SignOut
public ActionResult SignOut()
{
FormsAuthentication.SignOut();
if (Request.Cookies[".MVCRETURNURL"] != null)
{
var returnUrlCookie = new HttpCookie(".MVCRETURNURL") { Expires = DateTime.Now.AddDays(-1d) };
Response.Cookies.Add(returnUrlCookie);
}
// Redirect back to sign in page so user can
// sign in with different credentials
return RedirectToAction("SignIn", "Account");
在global.asax中:
protected void Application_BeginRequest(object sender, EventArgs e)
{
try
{
bool cookieFound = false;
HttpCookie authCookie = null;
for (int i = 0; i < Request.Cookies.Count; i++)
{
HttpCookie cookie = Request.Cookies[i];
if (cookie.Name == ".MVCAUTH")
{
cookieFound = true;
authCookie = cookie;
break;
}
}
if (cookieFound)
{
// Extract the roles from the cookie, and assign to our current principal, which is attached to the HttpContext.
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);
HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(ticket), ticket.UserData.Split(';'));
}
}
catch (Exception ex)
{
throw;
}
}
protected void Application_AuthenticateRequest()
{
var returnUrl = Request.QueryString["ReturnUrl"];
if (!Request.IsAuthenticated &&
!String.IsNullOrWhiteSpace(returnUrl))
{
var returnUrlCookie = new HttpCookie(".MVCRETURNURL", returnUrl) {HttpOnly = true};
Response.Cookies.Add(returnUrlCookie);
}
}
的web.config
<!--<authorization>
<deny users="?"/>
</authorization>-->
<authentication mode="Forms">
<forms name=".MVCAUTH" loginUrl="~/WinLogin/WinLogin2.aspx" timeout="30" enableCrossAppRedirects="true"/>
</authentication>
<membership defaultProvider="AspNetActiveDirectoryMembershipProvider">
<providers>
<add name="AspNetActiveDirectoryMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ADService" connectionProtection="Secure" enablePasswordReset="false" enableSearchMethods="true" requiresQuestionAndAnswer="true" applicationName="/" description="Default AD connection" requiresUniqueEmail="false" clientSearchTimeout="30" serverSearchTimeout="30" attributeMapPasswordQuestion="department" attributeMapPasswordAnswer="division" attributeMapEmail="mail" attributeMapUsername="sAMAccountName" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" passwordAnswerAttemptLockoutDuration="30" minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="1"/>
</providers>
</membership><machineKey decryptionKey="..." validationKey="..." /> </system.web><connectionStrings> <add name="ADService" connectionString="LDAP://SERVER:389"/></connectionStrings>
这可能会住在这个问题的底部,永远不会被发现,但我还是能够实现什么样的
被描述http://mvolo.com / IIS-70-twolevel认证与 - 表单的身份验证 - 和 - 窗口认证/
这是相当容易和简单。并不需要多个应用程序或饼干黑客,只是延长FormsAuthModule并使一些web.config中的变化。
我知道这是旧的文章 - 但一切都永远生活在互联网上
!不管怎样,我不得不从IIS6移动的旧网站IIS8。这是一个的WebForms网站,但我假定这个非常简单的解决方案是相同的。
我接收到的错误:无法转换类型“System.Security.Principal.WindowsIdentity”的目的为类型“System.Web.Security.FormsIdentity”
我所做的只是创建一个网站一个新的应用程序池。当创建此,我设置了托管管道模式,以“经典”。 (更多内容 - http://www.hanselman.com/blog/MovingOldAppsFromIIS6ToIIS8AndWhyClassicModeExists.aspx)不要忘记该网站的应用程序池设置为您刚刚创建的新池。