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

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

上一节已经讲述如何将用户数据存储在外部数据表中。
如果你需要更大的灵活性(通常没有这个必要了),也可以完全全抛开了foxtable自身的用户管理系统,自己重新设计一套用户管理系统。
本节内容完全采用SQL语言来实现,可以说是对SQL语言的一次大演练。

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

设计步骤

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

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

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

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

Public _UserName As String
Public
_UserGroup As String

_UserName用户保存当前登录用户的名称,_UserGroup用于保存该用户的分组。

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

窗口的AfterLoad事件代码为:

Dim cmd As New SQLCommand
Dim
dt As DataTable
Dim
lst As WinForm.ListBox = e.Form.Controls("ListBox1")
cmd.ConnectionName =
"User"
cmd.CommandText =
"SELECT DISTINCT Name From {Users}"
dt = cmd.ExecuteReader()

For
Each dr As DataRow In dt.Datarows
    lst.Items.Add(dr(
"Name"))
Next
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
    Dim
cmd As
New SQLCommand
    cmd.ConnectionName =
"User"
    cmd.CommandText =
"Delete From {Users} Where [Name] = '" & UserName & "'"
    cmd.ExecuteNonQuery
    lst.Items.RemoveAt(lst.SelectedIndex)
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
cmd As New SQLCommand
cmd.ConnectionName =
"User"
If
UserName = "" OrElse UserGroup = "" Then
    Messagebox.show(
"请输入用户名和用户分组!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
    Return
End
If
cmd.CommandText =
"Select Count(*) From {Users} Where Name = '" & UserName & "'"
If
cmd.ExecuteScalar > 0 Then
    Messagebox.show(
"增加用户失败,已经能存在同名用户!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
    Return
End
If
cmd.CommandText =
"Insert Into {Users} ([Name],[Group],[Password]) Values ('"
cmd.CommandText = cmd.CommandText & UserName &
"','" & UserGroup & "','" & Password & "')"
If
cmd.ExecuteNonQuery = 1 Then '返回1表示增加成功
   
If Forms("用户管理").Opened Then
       
With Forms("用户管理").Controls("ListBox1")
            .Items.Add(UserName)
            .SelectedIndex = .Items.Count -
1
       
End With
   
End If
    e.Form.Close()

End
If

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

窗口的AfterLoad事件代码为:

Dim UserName As String
Dim
UserGroup As String
Dim
PassWord As String
Dim
cmd As New SQLCommand
Dim
dt As DataTable
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
cmd.ConnectionName =
"User"
cmd.CommandText =
"Select * From {Users} Where [Name] = '" & UserName & "'"
dt = cmd.ExecuteReader

If
dt.DataRows.Count = 1 Then
    e.Form.Controls(
"UserName").Value = UserName
    e.Form.Controls("UserGroup").Value = dt.DataRows(0)("Group")
    e.Form.Controls("PassWord").Value = dt.DataRows(0)("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
cmd As New SQLCommand
Dim
Parts() As String = e.Form.Text.Split("-")
OldUserName = Parts(Parts.Length -1)
cmd.ConnectionName = "User"

If
UserName = "" OrElse UserGroup = "" Then
    Messagebox.show(
"请输入用户名和用户分组!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
    Return
End
If
cmd.CommandText =
"Update {Users} Set [Name] = '" & UserName & "',[Group] = '" & UserGroup
cmd.CommandText = cmd.CommandText &
"', [Password] = '" & Password & "' Where [Name]= '" & OldUserName & "'"
If
cmd.ExecuteNonQuery = 1 Then '返回1表示更改成功
    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 cmd As New SQLCommand
Dim
dt As DataTable
Dim
cmb As WinForm.ComboBox = e.Form.Controls("UserName")
cmd.ConnectionName =
"User"
cmd.CommandText =
"SELECT DISTINCT Name From {Users}"
dt = cmd.ExecuteReader()

For
Each dr As DataRow In dt.Datarows
    cmb.Items.Add(dr(
"Name"))
Next

cmb.SelectedIndex =
0

"确定"按钮的代码为:

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
If
dt.DataRows.Count = 0 Then
    Messagebox.show("
此用户不存在!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
    Return

End
If
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

“取消”按钮的代码为:

e.Form.Close()

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

九、在项目事件AfterOpenProject中加入代码:

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

End If
'后续初始化代码

提示:为确保用户登录窗口为第一个打开的窗口,登录窗口的窗口类型必须设置为“模式”,且应该将其他所有独立或模式窗口的“自动打开”属性设置为False。

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

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

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

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

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

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

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

总结

经过上述10个步骤的设计,我们已经建立了自己的用户管理和登录系统,用户登录后,用户名保存在全局变量_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/2048.htm