2013-08-24 91 views
0

請告訴我用於驗證網絡用戶和存儲他們的詳細資料,我有一類的最佳方式:asp.net認證的WebForms

我應該使用會話或窗體身份驗證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 
+0

用戶登錄我已經實施了類似的在使用自定義標識的兩個項目中進行身份驗證(使用表單身份驗證票證),並且已經證明是更好的選擇來存儲您打算反覆使用每個請求的用戶數據。在你的其他文章中,我不明白你爲什麼不喜歡爲每個請求實例化一個自定義標識!你可以解釋嗎?你認爲可能有多重實例化客戶端身份? – Nilesh

+0

感謝您的回覆。在我看來,我必須爲每個請求對類實例化​​的用戶數據的任何自定義屬性做出錯誤。因此,例如userdata.firstname調用和userdata.lastname兩次創建類。你的是否這樣做。 – Jonnymaboy

+0

號你需要解密用戶數據,然後將所有單個對象initialization.Can您對帖子進行編輯和添加您如何實例化自定義主代碼中的屬性? – Nilesh

回答

1

正如你已經發布的代碼可能會得到一些很好的答案。我會盡力按照我的理解來回答,希望有所幫助。 如果沒有意義,我已經很久沒有和VB保持聯繫了。

  1. 從哪裏調用CustomIdentity?在Else部分的第一種方法中,我認爲如果您希望用戶重定向到登錄頁面,您可能需要使用Not IsAuthenticated。大多數情況下,如果票據無效,您甚至不必執行此操作,該框架可爲您提供幫助。
  2. CustomIdentityUser你有一個私人成員_Auth,你從來沒有使用,而通過屬性返回一些值。您正在使用Auth.UserName而不是_Auth.UserName,我不確定這是如何工作,除非用戶名是靜態成員。
  3. 你爲什麼要定製依賴於Auth的標識?您可以通過構造器或公開setters將所需數據傳遞給自定義標識。爲什麼你需要身份認證中的身份驗證票?
  4. Auth類具有到期日期和其他東西是不需要的。您可以使用簡單的User類來存儲用戶的基本信息。爲什麼你從Auth的構造函數重定向用戶?
  5. 我不知道GetUserDetailsSetUserDataFromString爲什麼你需要所有這些方法。它只是SerializingDeserializing User類的問題。

我知道您必須在那裏引用一些博客來實現此身份驗證,但您有很多範圍來簡化此操作。

閱讀this後。具體說明自定義主體如何實施以及如何設置authticket以及如何設置方法。

下面是一些示例代碼,這可能有助於

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); 
} 
+0

非常感謝你這個偉大的答案。爲了回答您的一些點: – Jonnymaboy

+0

1.我不真正調用調用,這是所謂的customidentity性質的訪問延期。 2,私人成員_auth被設置爲sub new,然後我有一個公共屬性auth。所以auth只是返回_auth。 3:你的權利根本不需要。 4:基本上我在這裏重定向,如果有任何問題獲取用戶的詳細信息和分配屬性,即如果一個cookie沒有過期,我改變了我需要用戶重新登錄的屬性順序。 5:我有額外的屬性取決於用戶類型。我會根據你的代碼做一個測試應用程序。鏈接到博客添加到問題。謝謝。 – Jonnymaboy

+0

該帖子有很多代碼,我可能忽略了一些屬性。 :)。希望我發佈的代碼可以幫助你,或者至少讓你有機會探索更多。 – Nilesh