ASP.NET MVCおよび混合モード認証
-
19-09-2019 - |
質問
私はWindows認証またはフォーム認証のいずれかを使用してASP.NET MVC Webアプリケーションに対して認証できるようにするには、ユーザーが必要となるシナリオを持っています。ユーザーは、内部ネットワーク上にある場合、それらはWindows認証を使用すると、彼らは外部に接続している場合、彼らは、フォーム認証を使用します。私は、このためのASP.NET MVC Webアプリケーションを設定するのですが、私は完全な説明を見つけることができますどのように質問をしてかなりの数の人々を見てきました。
誰かがこれが行われることになる方法については、コード例で、詳細な説明を提供することができますしてください?
感謝します。
アラン・T
解決
これは混合認証モードで呼ばれています。あなたは仮想ディレクトリのWindows認証を設定したら、IISで、それはもはや、異なるドメインからユーザーを負いませんので、基本的には、のシングルのアプリケーション内でこれを達成することはできません。だから、基本的には次の2つのアプリケーション、Windows認証とフォーム認証を使用して、第2(メインアプリケーション)との最初のを持っている必要があります。最初のアプリケーションは、単純に、ドメインユーザの認証チケットを発行することにより、メインアプリケーションにリダイレクトする単一のアドレスで構成されます。
他のヒント
このは行うことができます。このように、あなたが同じWebアプリケーション内で混合認証を設定することができます...匿名とフォーム認証を使用するようにアプリ/ルートを設定し、設定を元に戻しますが、それは難しいです。だから、最初、loginUrl =「〜/のWinLogin / WinLogin2.aspx」とフォーム認証のためのアプリあなたを設定します。 MVCでは、ルーティングは、IISが、ファイルの認証を設定することができますように、aspxページを使用する必要がある、IISで設定された認証ルールを上書きします。ルートWebアプリケーション上の匿名とフォーム認証を有効にします。 Windows認証を有効にし、ルート/ WinLoginのディレクトリに匿名認証を無効にします。バックアカウント/サインインもURLへリダイレクトするために、カスタム401と401.2エラーページを追加します。
このパススルー自動サインインにWindows統合認証を使用するのいずれかのブラウザが対応できるようになります。いくつかのデバイスは、(iPhoneなど)の認証情報とサインインページにリダイレクトブラックベリーのような他のデバイスの入力を求められますだろうが。
これはまた、明示的にユーザーの役割を追加するクッキーを作成し、役割ベースの許可を使用することができるように一般的な原則を作成します。
IISでのWinLogin2.aspx中(WinLoginのディレクトリにある「ルート」の下で、Webアプリケーション、およびオフにすることはできませんとWindows認証、匿名無効、およびフォームを有効にして(使用するように構成された...あなたが有効にするとIISが文句を言うだろう注意してくださいWindows認証だけ)を無視ます:
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では、このコードで、Redirect401.htmファイルのパスをファイルに401ページを設定し、エラーページをクリックします:
<!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://msdn.microsoft.com/en-usに負っクレジット/library/ms972958.aspxする
これはおそらく、この質問の下に住んでいるだろうし、見つかったことがないが、私は
で説明したものを実装することができましたhttp://mvolo.com / IIS-70-twolevel認証-と-フォーム認証と-Windowsの認証/ の
これはかなり簡単で、些細でした。ただFormsAuthModuleを拡張し、いくつかのweb.configファイルの変更を行う、複数のアプリケーションやクッキーのハックを必要としませんでした。
私は、これは古い記事です知っている - しかし、すべてがインターネット上で永遠に住んでいる。
!とにかく、私はIIS8にIIS6から古いWebサイトを移動しなければなりませんでした。これは、Webフォームのウェブサイトですが、私はこの非常に簡単な解決策は同じであると仮定します。
私は、エラーを受信:「System.Web.Security.FormsIdentity」を入力するタイプ「System.Security.Principal.WindowsIdentity」のオブジェクトをキャストすることができません。
。私がしたすべては、ウェブサイト用の新しいアプリケーションプールを作成しました。これを作成するとき、私は「クラシック」にマネージパイプラインモードを設定します。 (もっとここで読む - http://www.hanselman.com/blog/MovingOldAppsFromIIS6ToIIS8AndWhyClassicModeExists.aspx)作成したばかりの新しいプールにウェブサイトのアプリケーションプールを設定することを忘れてはいけない。