[英]ASP.Net MVC Custom Authentication
我有一個Asp.Net MVC webapplication坐在一個仍然主要由delphi管理的網站中。 安全性目前由delphi管理,它創建cookie。
已經決定通過提取cookie詳細信息並將它們傳遞給導入的Delphi DLL來驗證ASP.Net應用程序中的用戶,該DLL根據用戶是否有效返回true或false。
我的計划是使用Forms身份驗證,但不是將用戶重定向到表單而是調用delphi包裝器,如果成功,則將用戶重定向到原始URL。 這樣做的好處是,當安全性遷移到.Net時,身份驗證框架已經存在,只需要實現更改即可。
public ActionResult LogOn(SecurityCookies model, string returnUrl)
{
try
{
if (model != null)
{
Log.DebugFormat("User login: Id:{0}, Key:{1}", model.UserId, model.Key);
if (authenticator.UserValid(model.UserId, model.Key, 0))
{
FormsService.SignIn(model.UserId, false);
return Redirect(returnUrl);
}
}
...
請注意,SecurityCookies是由delphi生成的cookie中的自定義綁定類生成的 - 這很有效。
對delphi dll的調用也可以。
我必須克服的問題是幾乎所有對.Net應用程序的調用都是ajax請求。 但是,當用戶未登錄時,瀏覽器會因重定向而進行3次調用:1)原始ajax請求2)重定向到〜/ Account / Logon(上面的代碼)3)重定向回原來的ajax請求
雖然跟蹤回發給客戶端的響應,但顯示步驟3返回正確的數據,整個過程因尚未確定的原因而失敗。 只需單擊客戶端上的刷新即可,因為現在用戶已通過身份驗證,並且不會重定向到〜/ account / Logon。
注意我的客戶端jQuery代碼如下:$ .getJSON(requestString,function(data){//對數據執行某些操作});
有沒有辦法更改窗體身份驗證過程,以便在用戶未經過身份驗證時,而不是重定向到Url,我可以運行其他一些代碼? 我希望身份驗證已經發生在用戶的瀏覽器中完全不可見。
如果要對請求進行身份驗證,則可以通過定義Application_AuthenticateRequest方法在global.asax.cs中執行此操作。 在這里,您可以使用導入的delphi dll讀出自定義cookie並設置Context.User。 asp.net中的所有授權都基於HttpContext中設置的用戶。 Application_AuthenticateRequest方法的實現示例:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if(authCookie != null)
{
//Extract the forms authentication cookie
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
// Create an Identity object
//CustomIdentity implements System.Web.Security.IIdentity
CustomIdentity id = GetUserIdentity(authTicket.Name);
//CustomPrincipal implements System.Web.Security.IPrincipal
CustomPrincipal newUser = new CustomPrincipal();
Context.User = newUser;
}
}
如果cookie無效,那么您將不會在上下文中設置用戶。
然后,您可以創建一個BaseController,如果上下文中提供的用戶經過身份驗證,則所有控制器都將從該檢查繼承。 如果用戶未經過身份驗證,則可以返回HttpUnauthorizedResult。
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (User == null || (User != null && !User.Identity.IsAuthenticated))
{
filterContext.Result = new HttpUnauthorizedResult();
}
else
{
// Call the base
base.OnActionExecuting(filterContext);
}
}
}
在你的web.config中:
<authentication mode="None"/>
因為您不希望將請求重定向到登錄頁面。
我將回答這個具體問題的一部分
有沒有辦法更改窗體身份驗證過程,以便在用戶未經過身份驗證時,而不是重定向到Url,我可以運行其他一些代碼? 我希望身份驗證已經發生在用戶的瀏覽器中完全不可見。
不,那里沒有。 我編寫了一個類似於你的登錄系統,因為它是在表單身份驗證的基礎上構建的,而事實上沒有可擴展性點使它成為一個完整的PITA來編寫。
我能夠覆蓋內置行為的方式是使用HttpModule監視重定向到表單auth URL,然后攔截該操作並讓我處理它。
internal static bool IsFormsAuthenticationLogin(HttpResponseBase response)
{
if (!response.IsRequestBeingRedirected) return false;
if (string.IsNullOrWhiteSpace(response.RedirectLocation)) return false;
Uri formsAuthUri;
try
{
formsAuthUri = new Uri(FormsAuthentication.LoginUrl);
}
catch (Exception ex)
{
throw new XifCriticalException("Could not construct formsAuthUri", ex);
}
Uri redirctUri;
try
{
redirctUri = new Uri(response.RedirectLocation, UriKind.RelativeOrAbsolute);
}
catch (Exception ex)
{
throw new XifCriticalException("Could not construct redirctUri", ex);
}
try
{
//Check if the request was redirected by Forms Auth
bool isFormsAuthenticationLogin = redirctUri.IsAbsoluteUri &&
redirctUri.Host == formsAuthUri.Host
&& redirctUri.PathAndQuery.Contains(formsAuthUri.PathAndQuery);
return isFormsAuthenticationLogin;
}
catch (Exception ex)
{
throw new XifCriticalException("Could not construct isFormsAuthenticationLogin", ex);
}
}
另外需要注意的是,為了能夠在MVC3中依賴此代碼,您可能還需要指定應用程序設置
<add key="enableSimpleMembership" value="false" />
<add key="autoFormsAuthentication" value="false" />
幾件事。
首先,因為你顯然是在控制器動作中,所以你應該更換
Server.Transfer(returnUrl, true);
同
return Redirect(returnUrl);
其次,我通常更喜歡不使用ajax調用來進行身份驗證。 用戶應明確地從未經身份驗證的狀態轉移到經過身份驗證的狀態。
第三,如果你必須在通常進行重定向的地方進行ajax調用,你可以做兩件事之一。 在您的控制器中,您可以通過調用擴展方法IsAjaxRequest()來確定它是一個ajax請求(如果是,則返回true)並且如果它是ajax請求則分支不同的結果。 其次,如果你返回一個Redirect,那么它將向客戶端返回一個HTTP重定向,Ajax客戶端代碼應該能夠讀取並響應(例如,通過讀取Location然后對其進行ajax獲取)。 同樣,我不推薦這門課程,但這是可能的。
最后,作為一個完整的左轉...您是否考慮過單獨使用表單auth而不是使用自定義MembershipProvider? 您可以使用它來通過Delphi驗證成員資格,然后使用普通的FormsAuth對象設置客戶端cookie,就像它們在MVC中的示例AccountController中一樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.