代码之家  ›  专栏  ›  技术社区  ›  Jonnymaboy

asp.net用户身份验证的最佳方法网络表单

  •  0
  • Jonnymaboy  · 技术社区  · 11 年前

    验证网络用户并存储他们的详细信息的最佳方式是什么?我有一个类:

    我应该使用会话还是表单身份验证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
    

    然后,如您所见,用户类调用一个auth类,该类基本上包含用户的所有财产,并获取和设置它等。

    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
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Jonathan Hall    6 年前

    正如你发布的代码一样,你可能会得到一些好的答案。我会尽量按照我的理解来回答,希望这能有所帮助。

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

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

    阅读 this 邮递特别是如何实现自定义主体、如何设置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);
    }
    
    推荐文章