4

我正在创建一个新的 ASP.NET MVC 4 应用程序(实际上是我的第一个 MVC 应用程序),它是我以前的 ASP.NET Web 表单应用程序的一部分。我从未在我的任何项目中使用过 ASP.NET 内置身份验证方法。这个新的 MVC 4 应用程序将发布在以前应用程序的子域上。登录将从以前的应用程序完成。如果未登录,应从 MVC 应用程序提供返回 url 以返回到当前页面。但是,新用户注册、帐户恢复选项已经在以前的 Web 表单应用程序中开发,我不想在我的新 MVC 中复制它们应用。

token登录成功后,Web 表单应用程序将发出一个带有令牌编号的 cookie ,该 cookie 将共享给所有域,例如*.maindomain.com.

现在我想将我自己的令牌验证方法与 ASP.NET 内置方法合并,以便我可以Authorize在我的新 MVC 应用程序中使用其他与安全相关的选项。

在我之前的应用程序中,我以下列方式开发了我的自定义用户验证系统。

首先,我有以下相关的 SQL Server 表

在此处输入图像描述

和以下课程

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。

注意:成员类有一个属性bool IsAdmin。你知道它为什么。

请根据我在 MVC 应用程序中的需要建议我开发身份验证系统的最佳解决方案。我再次告诉您,类似New User,Account Recovery的选项Email Verification将在我之前的 ASP.NET Web 表单应用程序中完成。我只需要将我Validate()的类方法Token放在 MVC 应用程序中的正确位置即可。我真的对互联网上提供的几种解决方案感到困惑。

4

2 回答 2

8

如果您手动进行自己的身份验证,则安全性只能与您将 Ticket 安全地存储在客户端 cookie 中的方式一样强。

通常,您希望加密身份验证票证/令牌并通过 SSL 访问。只要您将 cookie 安全地存储在客户端,这应该不是问题。

我还想建议看看 ASP.Net 如何创建表单身份验证票。

注意:如果您使用 ASP.Net 表单身份验证票证,则不需要将票证/令牌存储在数据库中,因为用户将在每个页面请求时将身份验证票证发送到服务器。

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);

如何创建主体对象

一旦向经过身份验证的用户请求页面,您需要从 cookie 中检索身份验证票,并创建一个 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 保留为true(默认为true),它将自动增加过期时间。(阅读更多文章)

于 2013-08-07T16:12:54.867 回答
3

在高级简明概述中,您可以执行以下操作:

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

你可能采取的另一条路是重新评估你所拥有的。您基本上是在尝试为您的应用程序实现单点登录联合身份/身份验证。为此,我会推荐为此设计的解决方案。SAMLWS-Federation协议是提供此功能的两个流行标准。两种协议都或多或少地实现了相同的目标。

有很多基于这些协议的解决方案。

例如,一个是Windows Identity Foundation。从 .Net 4.5 开始,它集成在 .Net 框架中。在此之前可以单独下载。WIF 支持 WS-Federation 协议。在这里,一切都基于他们所谓的基于声明的安全性(通过下面的链接查看有关此主题的更多信息)。

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

重新评估您如何验证用户身份和管理他们的身份可能需要做很多工作。因此,由您决定是否值得投资。我必须完成,但这里有一些指向手头主题的更多链接:

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

于 2013-08-07T16:53:33.953 回答