开发与Web表单应用一致的自定义身份验证和授权系统。

4
我正在创建一个新的ASP.NET MVC 4应用程序(实际上是我的第一个MVC应用程序),它是我以前的ASP.NET Web Forms应用程序的一部分。我从未在任何项目中使用过ASP.NET内置的身份验证方法。这个新的MVC 4应用程序将发布在以前应用程序的子域上。登录将从以前的应用程序中完成。如果未登录,则需要从MVC应用程序提供返回URL以返回到当前页面。但是,在以前的Web表单应用程序中,已经开发了新用户注册、帐户恢复选项,我不想在我的新MVC应用程序中复制它们。
一个名为token的cookie将在Web表单应用程序成功登录事件上发出,共享给所有域,如*.maindomain.com
现在,我想将自己的令牌验证方法与ASP.NET内置方法合并,以便在我的新MVC应用程序中可以使用Authorize和其他安全相关选项。
在我的以前的应用程序中,我以以下方式开发了自定义用户验证系统。
首先,我有以下相关的SQL Server表 enter image description here 和以下类
public class Token
{
    public static uint GenerateToken(string userEmail, string password, bool isPersistent)
    {
        // this static function generates a uint type unique token number
        // and put this in the cookie "token" using HttpContext.Current.Response object.
        // if isPersistent is set to true then cookie will be persistent otherwise not
        // if there is any problem in creating token then it will throw an Exception with proper message
        // Possible causes of not generating a token are
        // 1. Invalid useremail or password
        // 2. 'State' value in 'Member' table is 'EmailPending' or 'Suspended' (there is an enum for MemberState
    }

    public Token(uint tokenNo, bool validateImmediately = false)
    {
        // simply load token details with a few filed from member table from database
        // Call validate function if validateImmediately is set to true
        // Throws an exception if token does not exists in the database
    }

    public void Validate()
    {
        // Checks for everything like MemberState is Active and Token status is also Active and throws exception if anything wrong
        // and then check (LastAccessedOn.AddSeconds(TokenLife) < AppSettings.Now) is not true
        // Call UpdateStatus function with new token status and current page from HttpContext in comment parameter
    }

    public void UpdateStatus((TokenStatus newStatus, string comment = "")
    {
        // simply write both newStatus and Comment in Token table
        // and remove the token cookie if newStatus is not set to Active
    }

    public uint TokenNumber { get; private set; }
    public uint MemberNumber { get; private set; } // from Member table
    public string Name { get; private set; } // from Member table
    public MemberState MemberState { get; private set; } // from Member table
    public string MemberEmail { get; private set; } // from member table
    public uint BusinsessNo { get; private set; } // from Business table
    public DateTime CreatedOn { get; private set; }
    public DateTime LastAccessedOn { get; private set; }
    public uint TokenLife { get; private set; } // from member
    public string CreatedIP { get; private set; }
    public string LastIP { get; private set; }
    public bool IsPersistent { get; private set; }
    public TokenStatus Status { get; private set; }
    public string Comment { get; private set; }
    public static Token Current
    {
        get
        {
            if (_t == null)
                _t = new Token(uint.Parse(HttpContext.Current.Request.Cookies["token"].Value));
            return _t;
        }
    }
    private static Token _t;
}

public class Member
{
     // all member related operations like new member, send verification email and verify email
}

为了登出用户,我只需调用UpdateStatus方法,如(TokenSatus.Closed, "User logged out")。该方法会处理cookie的删除。

注意:Member类有一个属性bool IsAdmin。你知道它是为什么的。

请为我提供在MVC应用程序中开发身份验证系统的最佳解决方案。我再次告诉你,像New UserAccount RecoveryEmail Verification这样的选项将在我的之前的ASP.NET Web Forms应用程序中完成。我只需要将Token类的Validate()方法放在MVC应用程序的正确位置即可。我真的对互联网上提供的几个解决方案感到困惑。


用户如何登录到以前的Web表单应用程序?换句话说,在以前的Web表单应用程序中,如何对用户进行身份验证和授权? - Win
@Win,有一个登录表单,它调用静态方法 Token.GenerateToken(...)。每次请求时都需要验证登录。我只需使用来自 token cookie 的 uint 值初始化 Token 对象并调用 Validate() 方法即可。Validate() 方法不返回任何内容。如果无法验证,则会抛出错误并删除 cookie,并更新新状态、最后访问时间和注释到数据库中。 - shashwat
2个回答

8
如果您手动编写身份验证程序,则安全性只能与客户端cookie中存储Ticket的方式一样强。通常情况下,您希望加密身份验证票证/令牌并通过SSL进行访问。只要在客户端安全地存储cookie,这就不是问题。 我还建议看看ASP.Net如何创建表单身份验证Ticket。注意:如果使用ASP.Net表单身份验证Ticket,则不需要将ticket/token存储在数据库中,因为用户会在每个页面请求上将auth ticket发送到服务器。
var now = DateTime.UtcNow.ToLocalTime();

var ticket = new FormsAuthenticationTicket(
                1, /*version*/
                MemberID,
                now,
                now.Add(FormsAuthentication.Timeout),
                createPersistentCookie,
                TokenID, /*custom data*/
                FormsAuthentication.FormsCookiePath);

var encryptedTicket = FormsAuthentication.Encrypt(ticket);

var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
{
   HttpOnly = true,
   Secure = FormsAuthentication.RequireSSL,
   Path = FormsAuthentication.FormsCookiePath
};

if (ticket.IsPersistent)
{
   cookie.Expires = ticket.Expiration;
}
if (FormsAuthentication.CookieDomain != null)
{
   cookie.Domain = FormsAuthentication.CookieDomain;
}

_httpContext.Response.Cookies.Add(cookie);

如何创建 Principal 对象

一旦认证用户请求页面,您需要从 cookie 中检索 auth ticket,并创建一个 Principal 对象。

// In Global.asax.cs
void Application_AuthenticateRequest(object sender, EventArgs e)
{
   HttpCookie decryptedCookie = 
      Context.Request.Cookies[FormsAuthentication.FormsCookieName];

   FormsAuthenticationTicket ticket = 
      FormsAuthentication.Decrypt(decryptedCookie.Value);

   var identity = new GenericIdentity(ticket.Name);
   var principal = new GenericPrincipal(identity, null);

   HttpContext.Current.User = principal;
   Thread.CurrentPrincipal =HttpContext.Current.User;
}

// In action method, how to check whether user is logged in 
if (User.Identity.IsAuthenticated)
{

}

我需要延长cookie到期时间吗?

如果您将slidingExpiration 保持为真(默认为真),它将自动增加过期时间。(请阅读文章了解更多信息)


如果我的托管帐户中没有SSL呢? - shashwat
好的,我有点明白了...?但是我该如何检查用户是否已登录呢..? - shashwat
@harsh - 如果你在没有SSL的情况下进行登录,那么你就是互联网上的安全隐患。你的用户账户很可能会有一天被攻击。 - Erik Funkenbusch
@SirajMansour 通常会进入 LoginButton_Click 事件 - 代码基本上创建了 FormsAuthenticationTicket,并将其保存在 cookie 中。 - Win
@Win 你能否帮我检查一下我在这里发布的问题: http://stackoverflow.com/questions/22933838/i-am-calling-an-asmx-web-service-from-javascript-and-it-is-preveting-my-session/22934730?noredirect=1#comment35012883_22934730尽管启用了cookies,并且身份验证模式设置为forms,但运行时没有特定于“FormsAuthentication.FormsCookieName”值的cookie,实际上HttpResponse对我来说没有任何cookie。 - sm_
显示剩余6条评论

3

简要概述,您可以执行以下操作:

如果您想继续使用现有内容,则最好的解决方案是编写自定义HTTP模块,用于处理MVC Web应用程序的身份验证。大多数身份验证模块(Windows、Forms等)都是通过HTTP模块完成的。在此处,您可以阅读请求和相应的cookie,并设置当前请求和线程的主体对象。此外,如果发生HTTP 401错误-因为未经身份验证的用户正在请求mvc webapp的安全资源-您可以将其重定向到其他web app的登录页面,并让他们将用户重定向回最初请求的那个。

您可以采取不同的方法来重新评估所拥有的内容。您基本上正在尝试实现单点登录和联合身份/身份验证,对于此,我建议使用专为此设计的解决方案。SAMLWS-Federation协议是两种流行的标准,可提供此功能。这两个协议实现了或多或少相同的目标。

有很多基于其中一个协议的解决方案。

举个例子,Windows Identity Foundation就是其中之一。从.Net 4.5开始,它已经集成在.Net框架中了。在此之前,需要单独下载。WIF支持WS-Federation协议。这里的一切都基于所谓的声明式安全(请通过下面的链接获取更多有关此主题的信息)。

SAML协议不受WIF支持,尽管存在一些旧库CTP版本。我不建议使用它。

重新评估如何验证用户并管理其身份可能需要大量工作。因此,由您决定是否值得投资。我必须结束了,但这里还有一些有关此主题的链接:

虽然这不是一个现成的答案,但我希望它能帮助你找到答案。祝你好运!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接