繁体   English   中英

ASP.Net MVC自定义身份验证

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM