[英]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.