0

验证网络用户和存储他们的详细信息的最佳方法是什么,我有一门课程:

我应该使用会话还是表单身份验证 cookie?

我如何从任何一种方式访问​​它,比如 userclass.username?

我想存储相当多的用户信息来停止对以下内容的数据库调用:用户类型、用户全名、地址、邮政编码、foo1、foo2、foo3、foo4 等等。我知道这可能会进入会话或身份验证 cookie 用户数据。这个问题与我有的https://stackoverflow.com/questions/18393122/whats-the-best-way-to-authenticate-a-user-and-store-user-details-sessions-or-fo相关并链接没有任何帮助

真的可以在这里得到一些帮助和建议,因为我有一些系统需要这样做。任何意见表示赞赏。

谢谢

************************************ 链接 ************* ******************

我的代码大致基于:

http://www.shawnmclean.com/blog/2012/01/storing-strongly-typed-object-user-profile-data-in-asp-net-forms-authentication-cookie/

http://www.danharman.net/2011/07/07/storing-custom-data-in-forms-authentication-tickets/

************************************ 编辑 ************* ******************

自定义身份模块

Public Module IdentityExtensions
Sub New()
End Sub

Private _CustomIdentityUser As CustomIdentityUser

<System.Runtime.CompilerServices.Extension> _
Public Function CustomIdentity(identity As System.Security.Principal.IIdentity) As CustomIdentityUser
    'If _CustomIdentityUser Is Nothing Then
    '_CustomIdentityUser = DirectCast(identity, CustomIdentityUser)
    _CustomIdentityUser = Nothing
    If identity.GetType = GetType(FormsIdentity) Then
        _CustomIdentityUser = New CustomIdentityUser(DirectCast(identity, FormsIdentity).Ticket)
    Else
        If identity.IsAuthenticated Then
            FormsAuthentication.RedirectToLoginPage()
        End If
    End If

    Return _CustomIdentityUser
End Function
End Module

我的自定义身份用户

Public Class CustomIdentityUser
Implements System.Security.Principal.IIdentity

Private ticket As System.Web.Security.FormsAuthenticationTicket
Private _Auth As Auth

Public Sub New(ticket As System.Web.Security.FormsAuthenticationTicket)
    Me.ticket = ticket
    _Auth = New projectabc.Auth(Me.ticket)
End Sub

Public ReadOnly Property Auth As Auth
    Get
        Return Me._Auth
    End Get
End Property
Public ReadOnly Property Username As String
    Get
        Return Auth.Username
    End Get
End Property

Public ReadOnly Property UserType As Enumerations.EnumUserType
    Get
        Return Auth.UserType
    End Get
End Property
Public ReadOnly Property OwnerType As Enumerations.EnumOwnerType
    Get
        Return Auth.OwnerType
    End Get
End Property


Public ReadOnly Property AuthenticationType As String Implements System.Security.Principal.IIdentity.AuthenticationType
    Get
        Return "Custom"
    End Get
End Property

Public ReadOnly Property IsAuthenticated As Boolean Implements System.Security.Principal.IIdentity.IsAuthenticated
    Get
        Return ticket IsNot Nothing
    End Get
End Property

Public ReadOnly Property Name As String Implements System.Security.Principal.IIdentity.Name
    Get
        Return Username
    End Get
End Property
End Class

然后你可以看到用户类调用了一个身份验证类,它基本上具有用户的所有属性,并获取和设置它等。

Public Class Auth
Inherits BaseUser

Public Property _ticket As Web.Security.FormsAuthenticationTicket
Public RememberMe As Boolean

Private _IssueDate As DateTime?
Public ReadOnly Property IssueDate As DateTime?
    Get
        Return _IssueDate
    End Get
End Property
Private _Expired As Boolean
Public ReadOnly Property Expired As Boolean
    Get
        Return _Expired
    End Get
End Property
Private _Expiration As DateTime?
Public ReadOnly Property Expiration As DateTime?
    Get
        Return _Expiration
    End Get
End Property

Public Sub New(ticket As System.Web.Security.FormsAuthenticationTicket)
    Me._ticket = ticket
    Dim SignOutUser As Boolean = False
    Try
        If Not GetUserDetails() Then
            SignOutUser = True
        End If
    Catch ex As Exception
        SignOutUser = True
    End Try
    If SignOutUser Then
        HttpContext.Current.Response.Redirect("~/", True)
        SignOut()
    End If
End Sub

Public ReadOnly Property IsAuthenticated() As Boolean
    Get
        Return HttpContext.Current.User.Identity.IsAuthenticated
    End Get
End Property

Public Function SetAuthCookie() As Int16
    Dim encTicket As String
    Dim userData As String = CreateUserDataString()
    If userData.Length > 0 And userData.Length < 4000 Then
        Dim cookiex As HttpCookie = FormsAuthentication.GetAuthCookie(MyBase.Username, True)
        Dim ticketx As FormsAuthenticationTicket = FormsAuthentication.Decrypt(cookiex.Value)

        'Dim newTicket = New FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, userData, ticket.CookiePath)
        'encTicket = FormsAuthentication.Encrypt(newTicket)

        'Use existing cookie. Could create new one but would have to copy settings over...
        'cookie.Value = encTicket
        'cookie.Expires = newTicket.Expiration.AddHours(24)

        'HttpContext.Current.Response.Cookies.Add(cookie)
        Dim ticket As New FormsAuthenticationTicket(1, ticketx.Name, DateTime.Now, ticketx.Expiration, False, userData, ticketx.CookiePath)
        encTicket = FormsAuthentication.Encrypt(ticket)
        cookiex.Value = encTicket
        'Dim cookie As New HttpCookie(FormsAuthentication.FormsCookieName, encTicket)

        HttpContext.Current.Response.Cookies.Add(cookiex)
    Else
        Throw New ArgumentOutOfRangeException("User data length exceeds maximum", New ArgumentOutOfRangeException)
    End If

    Return encTicket.Length
End Function

Public Function GetUserDetails() As Boolean
    Dim valid As Boolean = False      

    If _ticket IsNot Nothing Then
        With _ticket
            RememberMe = .IsPersistent
            Username = .Name
            _IssueDate = .IssueDate
            _Expired = .Expired
            _Expiration = .Expiration

            Try
                If .UserData.Length > 0 Then
                    valid = SetUserDataFromString(.UserData)
                Else
                    'we have a problem
                    Return False
                End If
            Catch ex As Exception
                'sign them out as they may have a cookie but the code may have changed so it errors thus make them login again.
                'SignOut()
                Throw ex

            End Try
        End With
    End If

    Return valid

End Function

Private Function CreateUserDataString() As String
    Dim sData As New System.Text.StringBuilder

    With sData
        .Append(MyBase.UserID)
        .Append("|") 'delimeter we are using
        .Append(Int16.Parse(MyBase.UserType))
        .Append("|")
        .Append(Int16.Parse(MyBase.Security))
        .Append("|") 'delimeter we are using
        .Append(MyBase.FirstName)
        .Append("|")
        .Append(MyBase.LastName) 
    .Append("|")
        .Append(MyBase.foo1)  
    .Append("|")
        .Append(MyBase.foo2) 
        .Append("|")            
        .Append(MyBase.foo3)  
    .Append("|")
        .Append(MyBase.foo4) 
    End With


    Return sData.ToString
End Function    

   Public Function SetUserDataFromString(userData As String) As Boolean
    Dim valid As Boolean = False
    Dim sData As New System.Text.StringBuilder
    'check we have a delimeter
    Dim arUserData As String() = userData.Split("|")
    Try


    If arUserData.Count >= 9 Then '9 because that the user only stuff
        With arUserData
            MyBase.UserID = arUserData(0)
            MyBase.UserType = arUserData(1)
            MyBase.Security = arUserData(2)
            MyBase.FirstName = arUserData(3)
            MyBase.LastName = arUserData(4)
            MyBase.foo1 = arUserData(5)
    MyBase.foo2 = arUserData(6)
    MyBase.foo3 = arUserData(7)
    MyBase.foo4 = arUserData(8)
        End With
        valid = True
    Else
        valid = False
        End If

    Catch ex As Exception
        Throw New ArgumentOutOfRangeException("User data length to short", New ArgumentOutOfRangeException)
    End Try
    Return valid
End Function

Public Sub SignOut()
    FormsAuthentication.SignOut()
End Sub
4

1 回答 1

1

正如您发布的代码,您可能会得到一些好的答案。我会根据我的理解尝试回答,希望对您有所帮助。

  1. 您从哪里调用 CustomIdentity?在 Else 部分的第一种方法中,Not IsAuthenticated如果您希望用户重定向到登录页面,我认为您可能想要使用。大多数情况下,如果票证无效,您甚至不必这样做,框架会为您完成。
  2. CustomIdentityUser您有一个私有成员 _Auth 时,您在通过属性返回一些值时从不使用它。您正在使用Auth.UserName而不是_Auth.UserName,除非 UserName 是静态成员,否则我不确定它是如何工作的。
  3. 为什么您的自定义身份依赖于Auth?您可以通过构造函数或公开 public 将所需数据传递给自定义身份setters。为什么需要身份内部的身份验证票?
  4. 该类Auth具有到期日期和其他不需要的东西。您可以有一个简单的User类来存储用户的基本详细信息。为什么要从 的构造函数中重定向用户Auth
  5. 而我GetUserDetailsSetUserDataFromString知道你为什么需要所有这些方法。它只是用户类的Serializing问题。Deserializing

我知道您一定已经参考了一些博客来实现此身份验证,但您有很大的空间来简化它。

阅读这篇文章。具体如何实现自定义主体以及如何设置 authticket 和PostAuthenticateRequest方法。

这是一些可能有帮助的示例代码

interface ICustomPrincipal : IPrincipal
{
    int UserId { get; set; }
    string FirstName { get; set; }
    string LastName { get; set; }
}

public class CustomPrincipal : ICustomPrincipal
{
    public CustomPrincipal()
    {

    }

    public CustomPrincipal(string userName)
    {
        Identity = new GenericIdentity(userName);
    }

    public int UserId
    {
        get;
        set;
    }

    public string FirstName
    {
        get;
        set;
    }

    public string LastName
    {
        get;
        set;
    }

    public IIdentity Identity
    {
        get;
        private set;
    }

    public bool IsInRole(string role)
    {
        return false;
    }

}

public class User
{
    public string UserName { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
}

public static class FormsAuthHelper
{
    public static void SetAuthTicket(User user, HttpContextBase context)
    {
        var serializer = new JavaScriptSerializer();
        var userData = serializer.Serialize(user);
        var authTicket = new FormsAuthenticationTicket(
            1, user.UserName,
            DateTime.Now, DateTime.Now.AddMinutes(30),
            false, userData);
        var ticket = FormsAuthentication.Encrypt(authTicket);
        var faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, ticket);
        context.Response.Cookies.Add(faCookie);
    }

    public static void Logout()
    {
        FormsAuthentication.SignOut();
        FormsAuthentication.RedirectToLoginPage();
    }

    public static CustomPrincipal GetPrincipal(User user)
    {
        return new CustomPrincipal(user.UserName) { FirstName = user.FirstName, LastName = user.LastName, UserId = user.EntityId };
    }
}

发布身份验证请求事件如下所示

 protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
 {
    var authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
    if (authCookie == null || authCookie.Value == string.Empty)
       return;

    try
    {
       var ticket = FormsAuthentication.Decrypt(authCookie.Value);
       var serializer = new JavaScriptSerializer();
       var user = serializer.Deserialize<User>(ticket.UserData);
       var newUser = FormsAuthHelper.GetPrincipal(user);

       HttpContext.Current.User = newUser; 
    }
    catch
    {
            //do nothing
    }
 }

最后当用户登录时

public ActionResult Login(LoginModel loginModel)
{
   if (ModelState.IsValid)
   {
      var user = _userRepository.Get(x => x.UserName == loginModel.UserName).SingleOrDefault();
      if (user != null && PasswordHash.ValidatePassword(loginModel.Password, user.Password))
      {
         FormsAuthHelper.SetAuthTicket(user, HttpContext);
         return RedirectToAction("Index", "Home");
      }
      ModelState.AddModelError("NotFound", "User not found");
   }
   return View(loginModel);
}
于 2013-08-25T02:55:38.873 回答