自定义用户与权限管理之二

一般用户请忽略本节内容。

上一节已经 讲述了如何自己设计用户管理系统,由于完全使用SQL语句来实现,对于一般的用户来说,可能有些困难。
本节实现完全一模一样的功能,但是基本上不使用SQL语句,而是采用Foxtable自己的后台数据处理函数,所以更简单,更适合一般用户掌握。
还是要申明一下,因为内置的用户数据可以存储在外部数据表中,所以多数情况下并没有必要自定义用户管理,只是通过这两个例子,让大家可以演练一下SQL语句和后台数据处理函数的使用方法。

本节内容可以参考CaseStudy目录下的文件"自定义用户管理之二.Table",用户信息保存在一个Access文件"用户.mdb"中。

设计步骤

一、在文件“用户.mdb”新建一个名为“Users”的表,包括Name、Group、Password三列,分别用于保存用户名、用户分组和密码 ,其中Name列设置为主键。

二、建立一个外部数据源,连接到文件“用户.mdb”,数据源的名称设置为“User”。

三、打开Foxtable的用户管理,增加一个用户,并将其设置为默认用户,这样打开项目的时候,将不会出现foxtable的用户登录窗口。
  提示:示例文件“自定义用户管理.Table"”菜单中的用户管理和用户登录,已经被自定义的用户管理和登录代替,必须先按Ctrl+Shift+F12回到系统菜单,才能打开Foxtable的用户管理。

四、在全局代码中定义两个变量:

Public _UserName As String '用户名
Public
_UserGroup As String '用户分组
Public
_UserTable As DataTable '用户表

_UserName用户保存当前登录用户的名称,_UserGroup用于保存该用户的分组,_UserTable是一个临时表,后面将基于此表读写后台的用户表。

五、在项目事件AfterOpenProject加上代码:

Dim cmd As New SQLCommand
cmd
.ConnectionName = "User"
cmd
.CommandText = "SELECT * From {Users} Where [Name] Is Null"
_UserTable
= cmd.ExecuteReader(True)

上面的代码基于后台的用户表生成一个临时表,这个临时表没有加载数据,后面将基于此表和后台的用户表进行交互。
注意这里要将
ExecuteReader的参数设置为True,因为我们需要增加、删除和修改用户 ,也就是说,不仅要读用户表,还要写用户表。

六、新建一个窗口名为“用户管理”窗口:

窗口的AfterLoad事件代码为:

Dim lst As WinForm.ListBox = e.Form.Controls("ListBox1")
lst
.ComboList = _UserTable.SQLGetComboListString("Name")
If
Lst.Items.Count > 0 Then
    lst.SelectedIndex =
0

End
If

"增加用户"按钮的代码为:

Forms("增加用户").Open()

"更改用户"按钮的代码为:

If e.Form.Controls("ListBox1").SelectedIndex >=0 Then
    Forms(
"更改用户").Open()
End
If

"删除用户“按钮的代码为:

Dim lst As WinForm.ListBox = e.Form.Controls("ListBox1")
If
lst.SelectedIndex >=0 Then
    Dim UserName As String = lst.SelectedItem
    _UserTable.SQLDeleteFor("[Name] = '" & UserName & "'")
   
_UserTable.RemoveFor("[Name] = '" & UserName & "'")
    lst.Items.RemoveAt(lst.SelectedIndex)
   
lst.Select()
End
If

七、新建一个名为"增加用户"的窗口:

"确定"按钮的代码设置为:

Dim UserName As String = e.Form.Controls("UserName").Value
Dim
UserGroup As String  = e.Form.Controls("UserGroup").Value
Dim
PassWord As String = e.Form.Controls("PassWord").Value
Dim
dr As DataRow
If
UserName = "" OrElse UserGroup = "" Then
    Messagebox.show(
"
请输入用户名和用户分组!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
   
Return

End
If
If
_UserTable.SQLFind("[Name] = '" & UserName & "'") IsNot Nothing Then
    Messagebox.show(
"
增加用户失败,已经能存在同名用户!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
   
Return

End
If
dr
= _UserTable.AddNew()
dr
("Name") = UserName
dr
("Group") = UserGroup
dr
("Password") = PassWord
_UserTable
.Save()
e
.Form.Close()
If
Forms("用户管理").Opened Then
    With Forms(
"
用户管理").Controls("ListBox1")
        .Items.Add(UserName)
        .SelectedIndex = .Items.Count -1
   
End With
End
If

八、新建一个名为“更改用户”的窗口:

窗口的AfterLoad事件代码为:

Dim UserName As String
Dim
UserGroup As String
Dim
PassWord As String
Dim
dr As DataRow
If
Forms("用户管理").Opened Then '正常打开
    UserName = Forms(
"
用户管理").Controls("ListBox1").SelectedItem
Else

   UserName = _UserName
'_UserName
为全局变量,用于保存当前用户名
   e.Form.Controls("UserName").Enabled = False
   e.Form.Controls("UserGroup").Enabled =
False

End
If
e
.Form.Text = e.Form.Text & "-" & UserName '将要更改的用户名保存在窗口标题中,方便其他事件调用
dr
= _UserTable.SQLFind("[Name] = '" & UserName & "'")
If
dr IsNot Nothing Then
    e.Form.Controls("UserName").Value = UserName
    e.Form.Controls("UserGroup").Value = dr("Group")
    e.Form.Controls("PassWord").Value = dr("PassWord")

Else

    MessageBox.Show("用户不存在或者已经被删除!","提示",MessageBoxButtons.OK)
    e.Form.Close()
End
If

上面的代码在打开“更改用户”窗口之前,先判断“用户管理”窗口是否已经打开,如果已经打开,则更改“用户管理”窗口中选定的用户;否则更改当前登录的用户,且禁止更改用户名和用户分组,只能更改用户密码。
这样当我们需要给登录用户提供更改密码功能的时候,只需增加一个菜单按钮,按钮代码设置为:Forms(
"更改用户").Open()

"确定"按钮的代码为:

Dim UserName As String = e.Form.Controls("UserName").Value
Dim
UserGroup As String  = e.Form.Controls("UserGroup").Value
Dim
PassWord As String = e.Form.Controls("PassWord").Value
Dim
OldUserName As String
Dim
Parts() As String = e.Form.Text.Split("-"c)
OldUserName =  Parts(Parts.Length -1)
If UserName = ""
OrElse UserGroup = "" Then
    Messagebox.show(
"
请输入用户名和用户分组!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
   
Return

End
If
Dim
dr As DataRow = _UserTable.SQLFind("[Name]= '" & OldUserName & "'")
If
dr IsNot Nothing Then
    dr("Name") = UserName
    dr("Group") = UserGroup
    dr("Password") = PassWord
    dr.Save()
    If Forms(
"
用户管理").Opened Then
        With Forms(
"
用户管理").Controls("ListBox1")
            .Items(.SelectedIndex) = UserName
        End With
    End If
   
e.Form.Close
Else

    Messagebox.show("更改用户失败!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)

End
If

九、增加一个名为“用户登录”的窗口:

窗口的AfterLoad事件代码为:

Dim cmb As WinForm.ComboBox = e.Form.Controls("UserName")
cmb
.ComboList = _UserTable.SQLGetComboListString("Name")

"确定"按钮的代码为:

Dim UserName As String = e.Form.Controls("UserName").Value
Dim
dr As DataRow
If
UserName = ""  Then
    Messagebox.show(
"
请选择用户!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
   
Return

End
If
dr
= _UserTable.SQLFind("[Name] = '" & UserName & "'")
If
dr Is Nothing Then
    Messagebox.show(
"
此用户不存在!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
   
Return

End
If
If
e.Form.Controls("PassWord").Value = dr("Password") Then
    _UserName = UserName
    _UserGroup = dr("Group")
   
e.Form.Close
Else

    Messagebox.show("密码错误!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)

End
If

为了防止用户跳过确定和取消按钮,直接关闭窗口,请将窗口的“显示控制框”属性设置为False。

十、将项目事件AfterOpenProject的代码改为:

Dim cmd As New SQLCommand
cmd
.ConnectionName = "User"
cmd
.CommandText = "SELECT * From {Users} Where [Name] Is Null"
_UserTable
= cmd.ExecuteReader(True)

Forms("用户登录").Open()
If
_UserName = "" Then
    Syscmd.Project.Exit()
    Return
'
这个要加上,因为既然要退出,就不应该再执行后面的初始化代码了,否则会出错
End
If
'后续初始化代码

第一段是之前已经写好的代码,第二段是新加上去的,为的是打开项目后能出现登录窗口。
为确保用户登录窗口为第一个打开的窗口,登录窗口的窗口类型必须设置为“模式”,且应该将其他所有独立或模式窗口的“自动打开”属性设置为False。

十一、最后修改菜单中的"用户管理"和"切换用户"按钮的代码,启用"用户管理"按钮的代码为:

Forms("用户管理").Open()

"切换用户"按钮的代码为:

Forms("用户登录").Open()

你可以先应用系统菜单“system.ribbon”,然后再修改。

如果需要,还可以增加一个更改密码的按钮,代码设置为:

Forms("更改用户").Open()

总结

经过上述11个步骤的设计,我们已经建立了自己的用户管理和登录系统,用户登录后,用户名保存在全局变量_User中,用户分组保存在全局变量_UserGroup中。

我们只需对原来的权限代码稍作修改,即可适用自定义的用户管理系统,例如原来的代码为:

If User.Group = "经理" Then
    DataTables
("表A").AllowEdit = True
Else
    DataTables
("表A").AllowEdit = False
End
If

现在只需改为:

If _UserGroup = "经理" Then
    DataTables
("表A").AllowEdit = True
Else
    DataTables
("表A").AllowEdit = False
End
If

可以看出,自定义的用户管理系统,在应用上和内置的不会有任何差别。

不过使用自定义用户管理系统的时候,需要注意 事件触发顺序,由于自定义的用户登录窗口是在AfterOpenProject事件中打开,意味着在此事件之前触发执行的事件,是不能使用_UserName和_UserGroup变量的。
例如有的用户希望使用动态加载功能,在用户登录后,订单表只加载业务员为登录用户的订单,所有在项目事件BeforeLoadInnerTable设置了代码:

If e.DataTableName = "订单" Then
    e.Filter =
"业务员 = '" & _UserName & "'"
End
If

结果重新打开项目后,发现订单表根本没有加载任何数据,如果在代码中用MessageBox显示一下合成的加载条件:

If e.DataTableName = "订单" Then
    e.Filter =
"业务员 = '" & _UserName & "'"
    MessageBox.Show(e.Filter)
End If


会发现合成的加载条件为:

业务员 = ''

为什么会这样呢?
这是因为BeforeLoadInnerTable是在
AfterOpenProject事件之前触发执行,此时_UserName还是空值。

显然 要实现我们的目标,得使用新的设计方法:

1、首先在BeforeLoadInnerTable事件加入下面的代码,确保订单表初始状态不会加载任何数据:

If e.DataTableName = "订单" Then
    e.Filter =
"[_Identify] Is Null"
End
If

2、然后修改用户登录窗口的“确定”按钮的代码,在后面加上加载数据的代码:

Dim UserName As String = e.Form.Controls("UserName").Value
Dim
cmd As New SQLCommand
Dim
dt As DataTable
Dim
dr As DataRow
cmd.ConnectionName =
"User"
If
UserName = "" Then
    Messagebox.show(
"请选择用户!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
    Return
End
If
cmd.CommandText =
"Select * From {Users} Where [Name] = '" & UserName & "'"
dt = cmd.ExecuteReader
dr = dt.DataRows(
0)
If
e.Form.Controls("PassWord").Value = dr("Password") Then
    _UserName = UserName
    _UserGroup = dr(
"Group")
    e.Form.Close

Else

    Messagebox.show(
"密码错误!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
End If

DataTables
("订单").LoadFilter = "业务员 = '" & _UserName & "'"
DataTables(
"订单").Load(
)

上面代码的最后两行,就是用于根据登录用户名动态加载订单表数据的:

DataTables("订单").LoadFilter = "业务员 = '" & _UserName & "'"
DataTables(
"订单").Load(
)

以下几个事件在AfterOpenProject事件之前触发执行:

BeforeOpenProject
BeforeConnectOuterDataSource
BeforeLoadInnerTable
BeforeLoadOuterTable
Initialize

另外 由于设置了默认用户,绕开了内置的登录窗口,而且菜单中的登录命令已经改为自定义的登录命令,所以用户将无法以开发者和管理员身份登录系统。
如果希望以开发者或管理员身份登录系统,可以在打开项目的过程中始终按住Ctrl键。
也可以考虑在菜单中另外加入一个系统登录命令,代码设置为:Syscmd.Project.Switchuser()

最后自定义用户登录显然不会触发LoadUserSetting事件,所以该事件中的代码应该移植到自定义用户登录窗口的"确定"按钮中。


本页地址:http://www.foxtable.com/webhelp/topics/2945.htm