65.9K
CodeProject 正在变化。 阅读更多。
Home

在 web.config 的自定义节中开发自定义 ASP.NET Membership 和 Role 提供程序以读取用户

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (31投票s)

2008年7月20日

CPOL

8分钟阅读

viewsIcon

130635

downloadIcon

2151

在本文中,我们将开发自定义的 Membership 和 Role 提供程序,它们将从 web.config 文件中的自定义配置节读取用户凭据。

引言

最近,我开发了一个小型 Web 应用程序,以便能够对我的内网 Web 服务器进行一些基本的文件管理。完成我的应用程序后,我想我应该添加某种安全措施,以防止其他网络用户篡改我的文件。因此,ASP.NET 安全性浮现在脑海中。唯一的问题是我想避免使用数据库,因此我无法使用默认的 SQL membership 和 role 提供程序。有数百篇关于如何创建自定义 membership 和 role 提供程序的文章,但它们都需要数据库来读取数据。我想要一些简单且相当安全的东西,所以我想我应该将我的用户和角色的数据保存在 ASP.NET 中最安全的文件中,也就是 web.config 文件。

第一部分,我们将开发一个自定义配置节,以便在 web.config 文件中存储角色和用户数据。第二部分,我们将简要实现 role 和 membership 提供程序,然后在最后一部分,我们将创建一个小型演示 Web 应用程序来查看安全模型如何工作。到本文结束时,您将能够使用所有现成的 ASP.NET 登录控件,甚至 ASP.NET 网站管理工具来配置您的访问规则。

第一部分:自定义配置节

当我开始使用提供程序模型时,我第一次遇到自定义配置节,说实话,我过去都是机械地配置整个东西,而不是真正理解幕后到底发生了什么。这时 Jon Rista 的系列文章《揭秘 .NET 2.0 配置的奥秘》就派上用场了。我建议至少阅读第一部分,如果您在这里感到困惑的话。

为了记录我们的用户名和密码,我们将在 web.config 中添加一个节,如下所示:

<configuration>
  ...
  <!-- This is the new section we have configured-->
  <CustomUsersSection>
    <!-- Which has 2 property the Roles-->
    <Roles>
      <!-- Roles is a collection so it has two entries-->
      <add RoleName="User"/>
      <add RoleName="Administrator"/>
    </Roles>
    <!-- and the users-->
    <Users>
      <!-- You may add here as many users as you like -->
      <add UserName="auser" Password="password" 
           Email="abot@home" Role="User"/>
      <add UserName="admin" Password="password" 
           Email="abot@home" Role="Administrator"/>
    </Users>
  </CustomUsersSection>
  ...
</configuration>

查看上述 XML 并用面向对象的思想思考一下,我们可以说它描述了一个名为 CustomUsersSection 的类,该类有两个属性:RolesUsersRolesUsers 是项目的集合。如果我们现在多留意一下 add 标签并观察属性,我们可以说以下 XML

<add rolename="User" />

表示一个类实例,其 RoleName 属性设置为值“User”,而以下 XML

<add username="auser" password="password" email="abot@home" role="User" />

表示另一个类的实例,该类具有以下属性和值:

  • UserName - auser
  • Password - password
  • Email - abot@home
  • Role - User

好了,这正是这一切的意义所在:一个类层次结构。上述 XML 中涉及五个类:一个代表节(UsersConfigurationSection),一个代表角色集合(CustomRolesCollection),一个代表角色的类(CustomRole),一个代表用户集合的类(CustomUsersCollection),最后,代表用户的类(CustomUser)。

我们将从 App_Code>Configuration> CustomRole.vb 文件中自解释的类 CustomRoleCustomRolesCollection 开始。

Namespace Configuration
    Public Class CustomRole
        Inherits ConfigurationElement

        <ConfigurationProperty("RoleName", IsRequired:=True)> _
        Public ReadOnly Property RoleName() As String
            Get
                Return MyBase.Item("RoleName")
            End Get
        End Property

    End Class

    Public Class CustomRolesCollection
        Inherits ConfigurationElementCollection

        Protected Overloads Overrides Function CreateNewElement() _
                  As System.Configuration.ConfigurationElement
            Return New CustomRole
        End Function

        Protected Overrides Function GetElementKey(ByVal element _
                  As System.Configuration.ConfigurationElement) As Object
            Return CType(element, CustomRole).RoleName
        End Function

        'It is generally necessary to provide 
        'an indexer accessible by numeric index. 
        Public Shadows ReadOnly Property Item(ByVal index _
                       As Integer) As CustomRole
            Get
                Return MyBase.BaseGet(index)
            End Get
        End Property

        'An indexer accessible by an element's key 
        'is also a useful convenience
        Public Shadows ReadOnly Property Item(ByVal rolename _
                       As String) As CustomRole
            Get
                Return MyBase.BaseGet(rolename)
            End Get
        End Property
    End Class
End Namespace

这两个类分别继承自 ConfigurationElementConfigurationElementCollection 类。ConfigurationElement 是一个具有属性的单一实体,而 ConfigurationElementCollectionConfigurationElement 的集合。在我们的例子中,CustomRole 类有一个名为 RoleNameReadOnly 属性,它实际上调用了基类的属性 RoleName。因此,框架读取 XML 属性并将其继承到属性中。创建属性时,请确保添加以下编译器声明:

<ConfigurationProperty("propertyname", IsRequired:=True)> _

另一方面,继承自 ConfigurationElementCollectionCustomRolesCollection 只需要实现 CreateNewElementGetElementKey 函数。这两个 item 属性的实现有助于从集合中检索项目,因为默认情况下,item 属性是私有的。

同理,我从 App_Code>Configuration>CustomUser.vb 文件中引用了 CustomUserCustomUsersCollection

Imports System.Web.Security
Namespace Configuration
    Public Class CustomUser
        Inherits ConfigurationElement

        <ConfigurationProperty("UserName", IsRequired:=True)> _
        Public ReadOnly Property UserName() As String
            Get
                Return MyBase.Item("UserName")
            End Get
        End Property

        <ConfigurationProperty("Password", IsRequired:=True)> _
        Public ReadOnly Property Password() As String
            Get
                Return MyBase.Item("Password")
            End Get
        End Property

        <ConfigurationProperty("Role", IsRequired:=True)> _
        Public ReadOnly Property Role() As String
            Get
                Return MyBase.Item("Role")
            End Get
        End Property

        <ConfigurationProperty("Email", IsRequired:=True)> _
        Public ReadOnly Property Email() As String
            Get
                Return MyBase.Item("Email")
            End Get
        End Property

        Public ReadOnly Property AspNetMembership(ByVal ProviderName _
                        As String) As System.Web.Security.MembershipUser
            Get
                Return New MembershipUser(ProviderName, Me.UserName, _
                       Me.UserName, Me.Email, "", "", True, False, _
                       Date.Now, Date.Now, Date.Now, Date.Now, Nothing)
            End Get
        End Property
    End Class

    Public Class CustomUsersCollection
        Inherits ConfigurationElementCollection

        Protected Overloads Overrides Function CreateNewElement() _
                  As System.Configuration.ConfigurationElement
            Return New CustomUser
        End Function

        Protected Overrides Function GetElementKey(ByVal element As _
                  System.Configuration.ConfigurationElement) As Object
            Return CType(element, CustomUser).UserName
        End Function

        'It is generally necessary to provide 
        'an indexer accessible by numeric index. 
        Public Shadows ReadOnly Property Item(ByVal _
                       index As Integer) As CustomUser
            Get
                Return MyBase.BaseGet(index)
            End Get
        End Property

        'An indexer accessible by an element's key 
        'is also a useful convenience
        Public Shadows ReadOnly Property Item(ByVal username _
                                As String) As CustomUser
            Get
                Return MyBase.BaseGet(username)
            End Get
        End Property
    End Class
End Namespace

对上述哲学的唯一补充是我在 CustomUser 中添加的 AspNetMembership 只读属性,它返回 Membership 提供程序所需的虚拟 System.Web.Security.MembershipUser。要为 CustomUser 添加另一个属性,只需在类中添加以下代码:

<ConfigurationProperty("UserName", IsRequired:=True)> _
Public ReadOnly Property AnotherProperty () As String
    Get
       Return MyBase.Item("AnotherProperty ")
    End Get
End Property

并且,别忘了在 web.config 文件中完成属性设置。

最后一个类位于 App_Code>Configuration>UsersConfigurationSection.vb 文件中,它处理我们创建的整个配置节,因此继承自 ConfigurationSection

Imports System.Configuration
Namespace Configuration
    Public Class UsersConfigurationSection
        Inherits ConfigurationSection

        <ConfigurationProperty("Roles")> _
        Public ReadOnly Property Roles() As CustomRolesCollection
            Get
                Return MyBase.Item("Roles")
            End Get
        End Property

        <ConfigurationProperty("Users")> _
        Public ReadOnly Property Users() As CustomUsersCollection
            Get
                Return MyBase.Item("Users")
            End Get
        End Property

        Public Shared ReadOnly Property Current() _
                      As UsersConfigurationSection
            Get
                Return ConfigurationManager.GetSection("CustomUsersSection")
            End Get
        End Property

    End Class
End Namespace

您可能已经注意到,RolesUsers 属性是节的配置属性。我还添加了一个共享的只读属性 current,以便使用 ConfigurationManager 类获取保存在 web.config 文件中的名为“CustomUsersSection”的实例。

因此,到目前为止,我们有了整个类层次结构,我们需要指示 .NET 框架 web.config 文件中有一个新的节,它是 UsersConfigurationSection 类型,并且它的名称将是“CustomUsersSection”。如果我们查看提供的 web.config 文件的 configuration 标签正下方,我们将看到以下指令:

<ConfigSections >
    <section name="CustomUsersSection" 
        type="Configuration.UsersConfigurationSection, App_Code" />
</ConfigSections>

这正是我们想要的。不要被 Configuration 命名空间吓到,我只是想把类打包到一个命名空间下。

最终的 web.config 文件将如下所示:

<configuration>
    <ConfigSections>
        <section name="CustomUsersSection" 
               type="Configuration.UsersConfigurationSection, App_Code" />
    </ConfigSections>
    <CustomUsersSection>
        <roles>
            <add rolename="User" />
            <add rolename="Administrator" />
        </roles>
        <users>
            <add role="User" email="abot@home" 
                   password="password" username="auser" />
            <add role="Administrator" email="abot@home" 
                   password="password" username="admin" />
        </users>
    </CustomUsersSection>
    ...
</configuration />

第二部分:自定义 Membership 和 Role 提供程序

如果您在网上搜索“Custom Membership Provider”这三个关键词,您会找到数百万个页面和博客描述如何构建自定义 Membership 提供程序。这主要是通过继承抽象的 RoleProviderMembershipProvider 类,然后重写必需的函数来完成的。在我们的例子中,我们不会提供修改用户和角色的能力,因此我们将抛出许多 NotSupportedException 异常 :-)。任何其他自定义 membership 提供程序与此实现的根本区别在于,数据来自只读属性 UsersConfigurationSection.Current.UsersUsersConfigurationSection.Current.Roles。因此,WebConfigMembershipProvider 类(App_Code>AspNetProvider>WebConfigMembershipProvider.vb)看起来应该像这样(欢迎进行大量优化):

Imports Configuration
Namespace AspNetProvider
    Public Class WebConfigMembershipProvider
        Inherits MembershipProvider

        Private _ApplicationName As String

        Public Overrides Sub Initialize(ByVal name As String, _
               ByVal config As System.Collections.Specialized.NameValueCollection)
            '===retrives the attribute values set in
            'web.config and assign to local variables===
            _ApplicationName = config("ApplicationName")
            MyBase.Initialize(name, config)
        End Sub

        Public Overrides Property ApplicationName() As String
            Get
                Return _ApplicationName
            End Get
            Set(ByVal value As String)
                _ApplicationName = value
            End Set
        End Property

        Public Overrides Function ChangePassword(ByVal username As String, _
               ByVal oldPassword As String, ByVal newPassword As String) As Boolean
            Throw New System.NotSupportedException("No saving ")
        End Function

        Public Overrides Function ChangePasswordQuestionAndAnswer(ByVal username As String, _
               ByVal password As String, ByVal newPasswordQuestion As String, _
               ByVal newPasswordAnswer As String) As Boolean
            Throw New System.NotSupportedException("Not implemented")
        End Function

        Public Overrides Function CreateUser(ByVal username As String, _
               ByVal password As String, ByVal email As String, _
               ByVal passwordQuestion As String, ByVal passwordAnswer As String, _
               ByVal isApproved As Boolean, ByVal providerUserKey As Object, _
               ByRef status As System.Web.Security.MembershipCreateStatus) _
               As System.Web.Security.MembershipUser
            Throw New System.NotSupportedException("Not implemented")
        End Function

        Public Overrides Function DeleteUser(ByVal username As String, _
               ByVal deleteAllRelatedData As Boolean) As Boolean
            Throw New System.NotSupportedException("Not implemented")
        End Function

        Public Overrides ReadOnly Property EnablePasswordReset() As Boolean
            Get
                Return False
            End Get
        End Property

        Public Overrides ReadOnly Property EnablePasswordRetrieval() As Boolean
            Get
                Return False
            End Get
        End Property

        Public Overrides Function FindUsersByEmail(ByVal emailToMatch As String, _
               ByVal pageIndex As Integer, ByVal pageSize As Integer,  _
               ByRef totalRecords As Integer) As System.Web.Security.MembershipUserCollection
            Dim output As New System.Web.Security.MembershipUserCollection
            For Each user As CustomUser In UsersConfigurationSection.Current.Users
                If user.Email.Equals(emailToMatch) Then
                    output.Add(user.AspNetMembership(Me.Name))
                End If
            Next
            Return output
        End Function

        Public Overrides Function FindUsersByName(ByVal usernameToMatch As String, _
               ByVal pageIndex As Integer, ByVal pageSize As Integer,  _
               ByRef totalRecords As Integer) As System.Web.Security.MembershipUserCollection
            Dim output As New System.Web.Security.MembershipUserCollection
            For Each user As CustomUser In UsersConfigurationSection.Current.Users
                If user.UserName.Equals(usernameToMatch) Then
                    output.Add(user.AspNetMembership(Me.Name))
                End If
            Next
            Return output
        End Function

        Public Overrides Function GetAllUsers(ByVal pageIndex As Integer, _
               ByVal pageSize As Integer, ByRef totalRecords As Integer)  _
               As System.Web.Security.MembershipUserCollection
            Dim output As New System.Web.Security.MembershipUserCollection
            For Each user As CustomUser In UsersConfigurationSection.Current.Users
                output.Add(user.AspNetMembership(Me.Name))
            Next
            Return output
        End Function

        Public Overrides Function GetNumberOfUsersOnline() As Integer
            Throw New System.NotSupportedException("No saving ")
        End Function

        Public Overrides Function GetPassword(ByVal username As String, _
               ByVal answer As String) As String
            Throw New System.NotSupportedException("The question/answer" & _ 
                             " model is not supported yet!")
        End Function

        Public Overloads Overrides Function GetUser(ByVal providerUserKey As Object, _
               ByVal userIsOnline As Boolean) As System.Web.Security.MembershipUser
            Dim output As System.Web.Security.MembershipUser = Nothing
            For Each user As CustomUser In UsersConfigurationSection.Current.Users
                If user.UserName.Equals(providerUserKey) Then
                    output = user.AspNetMembership(Me.Name)
                End If
            Next
            Return output
        End Function

        Public Overloads Overrides Function GetUser(ByVal username As String, _
               ByVal userIsOnline As Boolean) As System.Web.Security.MembershipUser
            Dim output As System.Web.Security.MembershipUser = Nothing
            For Each user As CustomUser In UsersConfigurationSection.Current.Users
                If user.UserName.Equals(username) Then
                    output = user.AspNetMembership(Me.Name)
                End If
            Next
            Return output
        End Function

        Public Overrides Function GetUserNameByEmail(ByVal email As String) As String
            Dim output As String = Nothing
            For Each user As CustomUser In UsersConfigurationSection.Current.Users
                If user.Email.Equals(email) Then
                    output = user.UserName
                End If
            Next
            Return output
        End Function

        Public Overrides ReadOnly Property MaxInvalidPasswordAttempts() As Integer
            Get
                Return 5
            End Get
        End Property

        Public Overrides ReadOnly Property _
               MinRequiredNonAlphanumericCharacters() As Integer
            Get
                Return 0
            End Get
        End Property

        Public Overrides ReadOnly Property MinRequiredPasswordLength() As Integer
            Get
                Return 8
            End Get
        End Property

        Public Overrides ReadOnly Property PasswordAttemptWindow() As Integer
            Get
                Return 30
            End Get
        End Property

        Public Overrides ReadOnly Property PasswordFormat() _
               As System.Web.Security.MembershipPasswordFormat
            Get
                Return MembershipPasswordFormat.Clear
            End Get
        End Property

        Public Overrides ReadOnly Property _
               PasswordStrengthRegularExpression() As String
            Get
                Return ""
            End Get
        End Property

        Public Overrides ReadOnly Property RequiresQuestionAndAnswer() As Boolean
            Get
                Return False
            End Get
        End Property

        Public Overrides ReadOnly Property RequiresUniqueEmail() As Boolean
            Get
                Return False
            End Get
        End Property

        Public Overrides Function ResetPassword(ByVal username As String, _
                         ByVal answer As String) As String
            Throw New System.NotSupportedException("No saving")
        End Function

        Public Overrides Function UnlockUser(ByVal userName As String) As Boolean
            Throw New System.NotSupportedException("No saving")
        End Function

        Public Overrides Sub UpdateUser(ByVal user As System.Web.Security.MembershipUser)
            Throw New System.NotSupportedException("No saving")
        End Sub

        Public Overrides Function ValidateUser(ByVal username As String, _
                         ByVal password As String) As Boolean
            Dim output As Boolean = False
            If username.Length > 0 Then
                Dim myUser As CustomUser = _
                           UsersConfigurationSection.Current.Users.Item(username)
                If myUser IsNot Nothing Then
                    output = myUser.Password.Equals(password)
                End If
            End If
            Return output
        End Function
    End Class
End Namespace

WebConfigRoleProvider 类(App_Code>AspNetProvider>WebConfigRoleProvider.vb)如下:

Imports Configuration

Namespace AspNetProvider

    Public Class WebConfigRoleProvider
        Inherits RoleProvider

        Private _ApplicationName As String

        Public Overrides Sub Initialize(ByVal name As String, ByVal config _
                         As System.Collections.Specialized.NameValueCollection)
            '===retrives the attribute values set in           
            'web.config and assign to local variables===
            _ApplicationName = config("ApplicationName")
            MyBase.Initialize(name, config)
        End Sub

        Public Overrides Sub AddUsersToRoles(ByVal usernames() As String, _
                                             ByVal roleNames() As String)
            Throw New System.NotSupportedException("No saving")
        End Sub

        Public Overrides Property ApplicationName() As String
            Get
                Return _ApplicationName
            End Get
            Set(ByVal value As String)
                _ApplicationName = value
            End Set
        End Property

        Public Overrides Sub CreateRole(ByVal roleName As String)
            Throw New System.NotSupportedException("No saving")
        End Sub

        Public Overrides Function DeleteRole(ByVal roleName As String, _
               ByVal throwOnPopulatedRole As Boolean) As Boolean
            Throw New System.NotSupportedException("No saving")
        End Function

        Public Overrides Function FindUsersInRole(ByVal roleName As String, _
               ByVal usernameToMatch As String) As String()
            Dim output As New ArrayList
            For Each user As CustomUser In UsersConfigurationSection.Current.Users
                If user.Role.Equals(roleName) AndAlso _
                        user.UserName.Equals(usernameToMatch) Then
                    output.Add(user.UserName)
                End If
            Next
            Return output.ToArray(GetType(String))
        End Function

        Public Overrides Function GetAllRoles() As String()
            Dim myRoles As New ArrayList
            For Each role As CustomRole In UsersConfigurationSection.Current.Roles
                myRoles.Add(role.RoleName)
            Next
            Return myRoles.ToArray(GetType(String))
        End Function

        Public Overrides Function GetRolesForUser(ByVal username As String) As String()
            Dim user As CustomUser = _
                     UsersConfigurationSection.Current.Users.Item(username)
            If user IsNot Nothing Then
                'Only one role per user is currently supported
                Return New String() {user.Role}
            Else
                  Return New String() {}
            End If
        End Function

        Public Overrides Function GetUsersInRole(ByVal roleName As String) As String()
            Dim output As New ArrayList
            For Each user As CustomUser In UsersConfigurationSection.Current.Users
                If user.Role.Equals(roleName) Then
                    output.Add(user.UserName)
                End If
            Next
            Return output.ToArray(GetType(String))
        End Function

        Public Overrides Function IsUserInRole(ByVal username As String, _
                         ByVal roleName As String) As Boolean
            Dim user As CustomUser = UsersConfigurationSection.Current.Users.Item(username)
            If user IsNot Nothing Then
                Return user.Role.Equals(roleName)
            Else
                Return False
            End If
        End Function

        Public Overrides Sub RemoveUsersFromRoles(ByVal usernames() As String, _
                         ByVal roleNames() As String)
            Throw New System.NotSupportedException("No saving")
        End Sub

        Public Overrides Function RoleExists(ByVal roleName As String) As Boolean
            Return UsersConfigurationSection.Current.Roles.Item(roleName) IsNot Nothing
        End Function
    End Class

End Namespace

希望这些函数是自解释的,因为它们的名字非常具有描述性。为了完整起见,我将引用 web.config 中使用自定义提供程序所需的配置。整个配置在 configuration>system.web 节中进行,看起来像这样:

       <!--
            The <authentication> section enables configuration 
            of the security authentication mode used by 
            ASP.NET to identify an incoming user. 
            In our case the authentication will be handled by a login form-->
      <authentication mode="Forms"/>
      <!-- We define the rolemanager that will be handling the website's roles requests-->
      <roleManager enabled="true" defaultProvider="WebConfigRoleProvider">
        <providers>
          <!-- Clear the providers inherited by either 
               the machine.config or any parent application-->
          <clear/>
          <!-- Add our custom role provider-->
          <add name="WebConfigRoleProvider" 
            type="AspNetProvider.WebConfigRoleProvider" applicationName="WebSite"  _ 
            enabled="true" cacheRolesInCookie="true" cookieName=".ASPROLES" 
            cookieTimeout="30" cookiePath="/" cookieRequireSSL="false" _ 
            cookieSlidingExpiration="true" cookieProtection="All" />
        </providers>
      </roleManager>
      <!-- And here we define the custom membership provider-->
      <membership defaultProvider="WebConfigMembershipProvider">
        <providers>
          <clear/>
          <add name="WebConfigMembershipProvider" 
               type="AspNetProvider.WebConfigMembershipProvider" 
               applicationName="Website"/>
        </providers>
      </membership>

第三部分:演示 Web 应用程序

作为概念验证,我构建了一个不允许匿名用户的网站(请参阅 web.config 文件中的 authorization 节)。因此,当用户访问网站时,他会被重定向到登录表单。

login.aspxdefault.aspx 页面都利用了工具箱中“Login”选项卡中的控件,如下图所示:

Common login controls

最有趣的几行代码是:

  • My.User.Name:获取用户名
  • My.User.IsInRole("Administrator"):检查登录用户是否为管理员
  • Configuration.UsersConfigurationSection.Current.Users.Item(my.User.Name).Email:获取用户的电子邮件地址

最后,我应该指出,您可以使用 ASP.NET 网站管理工具来配置网站目录的访问规则。

Asp.net Web Site Administration Tool

结论

在本文中,我们看到了一种实现 membership 和 role 提供程序的新颖方法。用户凭据存储在 web.config 文件中的自定义配置节中,我们能够使用现成的登录控件来验证用户。

Possible Enhancements

给定代码的一个主要的可能增强是允许更新用户和角色。保存配置更改的方法在本文中讨论。

此外,可能的安全更新是对密码进行加密或哈希处理。我个人更喜欢对密码进行哈希处理,因为它更安全。要验证用户,将用户提供的密码进行哈希处理并与存储的哈希值进行比较。在这种情况下,我们需要添加一个名为 Hashing 的新类:

Imports System.Security.Cryptography
Imports System.Text
Public Class Hashing
    Public Shared Function HashInMD5(ByVal cleanString As String) As String
        Dim clearBytes As [Byte]()
        clearBytes = New UnicodeEncoding().GetBytes(cleanString)
        Dim hashedBytes As [Byte]() = _
            CType(CryptoConfig.CreateFromName("MD5"), _
            HashAlgorithm).ComputeHash(clearBytes)
        Dim hashedText As String = BitConverter.ToString(hashedBytes)
        Return hashedText
    End Function

End Class

然后在 WebConfigMembershipProvider.vb 文件中,我们需要将 ValidateUser 函数更改为以下内容:

Public Overrides Function ValidateUser(ByVal username As String, _
                 ByVal password As String) As Boolean
    Dim output As Boolean = False
    If username.Length > 0 Then
        Dim myUser As CustomUser = _
            UsersConfigurationSection.Current.Users.Item(username)
        If myUser IsNot Nothing Then
            output = myUser.Password.Equals(Hashing.HashInMD5(password))
        End If
    End If
    Return output
End Function

感谢论坛中与about:blank / colin的讨论,我被提示修改代码以支持为用户分配多个角色。要查找更改,请查找 '=========CHANGE HERE=============' 注释。

反馈和投票

如果您读到这里,请记住投票。无论您喜欢或不喜欢,同意或不同意本文中的内容,请在下方的论坛中说明。您的反馈至关重要,因为这是我的第一篇 CodeProject 文章!

历史

  • 2008 年 7 月 21 日:初版。
  • 2008 年 8 月 7 日:在可能的增强部分添加了对用户分配多个角色的支持。

附注:如果您不想实现 role 提供程序,那么您应该参考本文,该文使用内置的 .NET 身份验证模型来存储用户名和密码,但需要扩展才能支持角色。

© . All rights reserved.