万卷书>>电脑书籍>>程序设计>>pb程序设计>>PowerBuilder使用技巧集

WANJUANSHU.COM

实现PowerBuilder应用系统的一级安全性

浪 潮 集 团 计 算 机 事 业 本部
邢 剑 群



 

---- 数 据 库 的 安 全性 包 括 对 数 据 访 问 的 限 制。 未 经 授 权 的 用 户 不 能 访 问数 据 库, 还 有 些 用 户 不 能 访 问 该 数 据 库 的 某 些 部 分。在 应 用 系 统 中, 系 统 管 理 员 可 以 使 用“ 用 户 管 理” 模块, 为 应 用 系 统 建 立 多 个 用 户, 对 各 个 用 户 的“ 用 户号”、“ 用 户 名”、“ 口 令 字”、“ 网 络 地 址” 等 信 息 进行 维 护, 并 可 根 据 需 要 删 除 某 些 用 户; 系 统 管 理 员 使用“ 权 限 管 理” 模 块, 可 设 置 各 个 用 户 的 操 作 权 限。在 一 个 用 户 可 以 访 问 数 据 库 的 信 息 之 前, 该 用 户 必 须在 登 录 窗 口 中 表 明 自 己 是 一 个 合 法 用 户, 并 提 供 正 确口 令。 登 录 成 功 后, 用 户 可 以 运 行 已 经 授 权 的 模 块 功能, 访 问 相 应 的 数 据 库 信 息, 但 是 不 能 访 问 未 授 权 模块 所 对 应 的 数 据 库 信 息。 这 样, 就 为 应 用 程 序 提 供 了一 级 安 全 性。 当 然, 在 一 个 实 际 的 系 统 中, 可 以 借 助网 络 安 全 性 和 数 据 安 全 性 来 增 强 这 种 安 全 性。 权 限 管理 的 实 现 有 多 种 方 法, 例 如: 可 以 对 各 个 模 块 功 能 所需 权 限 级 别 进 行 定 义, 再 定 义 各 个 用 户 的 权 限 级 别(访 问 级 别), 在 每 个 选 单 项( 菜 单 项) 调 用 相 应 程 序前 先 判 断 当 前 用 户 级 别 是 否 大 于 或 等 于 该 选 单 项 运行 所 需 选 单 权 限 级 别, 若“ 大 于 或 等 于”, 则 运 行 相应 程 序, 否 则, 提 示“ 用 户 无 权 运 行 该 模 块 功 能”。 本文 将 介 绍 一 种 更 为 灵 活 的 方 法, 即 系 统 管 理 员 为 普 通用 户 设 置 可 选 菜 单 项, 当 用 户 进 入 应 用 系 统 时, 只 有其“ 可 选 菜 单 项” 显 示 出 来, 这 样 就 限 定 了 普 通 用 户对 应 用 系 统 各 个 模 块 的 使 用 权 限。 具 体 步 骤 如 下:


 

---- 1. 表 定 义:


 

---- 表 名:user_item


 

---- 作 用: 存 放 用户 信 息。 主 键 列 是“ 用 户 号” 列。


 


列代码列名           数据类型        空
————           ————        ————
usr_id           用户号 char(8)        NOT NULL
usr_name          用户名 char(20)       YES
usr_password       口令字 char(6)        YES


 

---- 表 名:menu_item


 

---- 作 用: 存 放 系统 菜 单 信 息。 主 键 列 是“ 菜 单 项 编 号” 列。


 


列代码           列名数据类型       空
————        ————————     ——
menu_id        菜单项编号 char(5)   NOT NULL
menu_text       菜单项文本 char(40)    YES


 

---- 表 名:menu_right


 

---- 作 用: 存 放 普通 用 户 可 使 用 菜 单 项 信 息。 主 键 列:“ 用 户 号” 和“ 用户 可 选 菜 单 项 编 号” 列。


 


列代码列名        数据类型           空
————       ————————       ——
usr_id        用户号 char(8)        NOT NULL
menu_id  用户可选菜单项编号char(5)  NOT NULL


 

---- 2. 表 与 表 之 间的 关 系:


 

---- user_item 表 和menu_right 表 的 关 系 是 一 对 多 的 关 系。menu_right 表 的“ 用 户 号” 列 是user_item 表 的 外 部 键。 如 果 用ERwin 创 建 表, 此“ 父- 子” 关 系 参 照完 整 性 定 义 为:


 


Trigger Action Type Trigger RI Option
CHID DELETE-----
CHID INSERT        RESTRICT
CHID UPDATE        RESTRICT
PARENT DELETE      CASCADE
PARENT INSERT      -----
PARENT UPDATE      CASCADE


 

---- 3. 创 建 索 引:


 

---- 以usr_id 列 为 索引 列 为user_item 表 建 立Unique Ascending 索 引。


 

---- 如 果 连 接 的 数据 库 是SYBASE 、INFORMIX 或 SQLServer, 以menu_id 列 为 索 引 列 为menu_item 表 建 立Unique Cluster Ascending 索 引,sql 语 句 为:


 

---- create UNIQUE CLUSTER INDEX XPKmenu_item on menu_item (menu_id ASC);。 以usr_id 列 和menu_id 列 为 索 引列 为menu_right 表 建 立Unique Cluster Ascending 索 引。 如 果 连 接 的 数据 库 是ORACLE 、WATCOMSQL(PowerBuilder5.0 中 改 名 为Sybase SQL Anywhere), 则 无 法 建 立Cluster 索 引。


 

---- 4. 对 象 的 属性:


 

---- PowerBuilder 是 面 向对 象 的 开 发 工 具, 采 用 事 件 驱 动 工 作 方 式, 利 用 对 象的 属 性 来 描 述 各 对 象 的 表 现 形 式 和 所 处 的 状 态。 在 应用 程 序 中, 可 以 根 据 需 求 的 不 同, 利 用 属 性 设 置 对 对象 作 不 同 的 处 理。 对 象 属 性 利 用 好 后, 可 以 很 好、 很简 捷 甚 至 无 需 编 程 就 能 满 足 一 些 特 殊 要 求。


 

---- 对 象 属 性 的 语法 为:Objectname.attribute


 

---- 本 文 所 述 程 序中 用 到 的 对 象 属 性:


 


窗口对象的属性名称     属性值类型       属性描述
MenuID       Menu型对象变量   指定菜单的标识号(ID)
菜单的属性名称        属性值类型       属性描述
Item[]    Menu型数组    指定菜单项
Text       字符串        指定菜单对象的文本内容


 

---- 5. 用 户 自 定 义函 数:


 

---- 函 数 名:f_get_menu


 

---- 作 用: 当 系 统管 理 员 运 行 应 用 系 统 时, 调 用 该 函 数, 可 把 系 统 菜 单信 息 存 放 到 表menu_item 中。


 

---- 函 数 定 义:


 

---- Access: Public Returns: None


 

---- Arguments Name: menu Type: menu Pass By: value 注 释: 系 统 主 窗 口 连 接 的 菜 单 标 识。


 

---- 函 数 内 容:


 


DELETE FROM menu_item  ;
int i,j,k,upper1,upper2,upper3
string id,text
//得到菜单数组的最高界,即一级菜单项个数
upper1=upperbound(menu.item)
for i=1 to upper1
//给一级菜单项编号
	id=string(i)+"0000"
//一级菜单项文本内容
	text=menu.item[i].text
//把一级菜单项信息存入表menu_item中
	INSERT INTO menu_item
	(menu_id,
	 menu_text)
	 values (:id,:text);
//upper2是第i个一级菜单项的下拉菜单项数
	upper2=upperbound(menu.item[i].item)
	for j=1 to upper2
//给二级菜单项编号
	  id=string(i)+string(j)+"000"
//二级菜单项文本内容
	  text=menu.item[i].text+"."+menu.item[i].item[j].text
	  //把二级菜单项信息存入表menu_item中
INSERT INTO menu_item
	  (menu_id,
	   menu_text)
	  VALUES(:id,
	    :text);
//upper3为第i个一级菜单项的第j个
二级菜单项的下拉菜单项数
	  upper3=upperbound(menu.item[i].item[j].item)
	  for k=1 to upper3
//给三级菜单项编号
id=string(i)+string(j)+string(k)+"00"
//三级菜单项文本内容
	  text=menu.item[i].text+"."+menu.item[i].item[j].text+"."&
+menu.item[i].item[j].item[k].text
//把三级菜单项信息存入表menu_item中
		  INSERT INTO menu_item
		  (menu_id,
		   menu_text)
		  VALUES(:id,
	  			:text);
	  next
	next
next


 

---- 注: 每 级 菜 单项 编 号 为1 至9, 即 每 级 菜 单 项 数 不 超 过9, 否 则 需 要 修改 此 函 数 内 容。


 

---- 对 超 过 三 级 的多 级 菜 单 需 要 修 改 此 函 数 内 容。


 

---- 函 数 名:f_test_menu


 

---- 作 用: 当 普 通用 户 运 行 应 用 系 统 时, 调 用 该 函 数, 可 把 该 用 户 不 可选 菜 单 项 设 为 不 可 见。


 

---- 函 数 定 义:


 


Access: Public     Returns: None
Arguments:
Name:       Type:    Pass By:   注释:
1  menu        menu     value      菜单标识
2  uidstring   value      用户号
函数内容:
string menu_id
//定义光标,查询用户不可选菜单项
DECLARE cur_noright CURSOR FOR
SELECT menu_item.menu_id
FROM menu_item
WHERE menu_item.menu_id not in
(  SELECT menu_right.menu_id
FROM menu_right
WHERE menu_right.usr_id = :uid  )
order by menu_id;
open cur_noright;
fetch cur_noright into :menu_id;
do while sqlca.sqlcode=0
//如果为一级菜单项则一级菜单项不可见,
一级菜单工具栏选项不可见
	if mid(menu_id,2,4 )="0000" then
		menu.item[integer(mid(menu_id,1,1))].visible=false
menu.item[integer(mid(menu_id,1,1))].toolbaritemvisible=false
	else
//如果为二级菜单项
		if mid(menu_id,3,3)="000" then
menu.item[integer(mid(menu_id,1,1))].item[integer(mid(&
menu_id,2,1))].visible=false
//二级菜单项不可见
menu.item[integer(mid(menu_id,1,1))
].item[integer(mid(menu_id,2,1&
))].toolbaritemvisible=false
//二级菜单工具栏选项不可见
else       		//如果为三级菜单项
	menu.item[integer(mid(menu_id,1,1))
].item[integer(mid(menu_id,2,1))].&
item[integer(mid(menu_id,3,1))].visible=false
//三级菜单项不可见
menu.item[integer(mid(menu_id,1,1))
].item[integer(mid(menu_id,2,1))].&
item[integer(mid(menu_id,3,1))].toolbaritemvisible=false
//三级菜单工具栏选项不可见
		end if
	end if
fetch cur_noright into :menu_id;
//取记录,光标下移一条
loop
close cur_noright;


 

---- 6. 创 建 授 权 窗口win_asyspermit:


 

---- 在win_asyspermit(Title 为“ 用 户 权 限 管 理”) 上 并 列 放 置 三 个 数 据 窗 口, 数 据窗 口 的Properties 中 选 择Vsible、Enabled、Hscroll Bar、Vscroll Bar、Live Scrolling:


 

---- dw_1 为dw_user, 显 示管 理 员 已 经 创 建 的 所 有 普 通 用 户 名,dw_user 的 语 法 为:


 


SELECT "user_item"."usr_id", "user_item"."usr_name"
FROM "user_item"
WHERE trim(user_item.usr_id) <> 'super'


 

---- 注:super 为 系 统管 理 员 的 用 户 号。dw_user 只 显 示usr_name 列 即 可。


 

---- dw_2 为dw_unright, 显示 用 户 不 可 选 菜 单 项,dw_unright 的 检 索 参 数 为 字 符 型uid, 代 表 用 户 号,dw_unright 的 语 法 为:


 


SELECT "menu_item"."menu_text", "menu_item"."menu_id"
FROM "menu_item"
WHERE menu_item.menu_id not in
(  SELECT "menu_right"."menu_id"
FROM "menu_right"
WHERE menu_right.usr_id = :uid  )
ORDER BY "menu_item"."menu_id" ASC
注:如果已对表menu_item创建了聚簇索引,
则可略去ORDER BY "menu_item"."menu_id" ASC
dw_unright只显示menu_text列即可。


dw_3为dw_user_right,显示用户可选菜单项, dw_user_right的检索参数为字符型uid,代表用户号, dw_user_right的语法为: SELECT "menu_right"."usr_id", "menu_right"."menu_id", "menu_item"."menu_text" FROM "menu_right", "menu_item" WHERE ( "menu_right"."menu_id" = "menu_item"."menu_id" ) and ( ( menu_right.usr_id = :uid ) ) ORDER BY "menu_right"."menu_id" ASC 注:如果已对表menu_item创建了聚簇索引, 则可略去ORDER BY "menu_item"."menu_id" ASC dw_user_right只显示menu_item_menu_text列即可。

窗口win_asyspermit上定义实例变量string uid, 代表用户号。在窗口open事件中输入下列script: connect; settransobject(dw_1,sqlca) settransobject(dw_2,sqlca) settransobject(dw_3,sqlca) dw_1.retrieve() //dw_1中显示所有普通用户名 long rows rows=dw_1.rowcount() if rows >0 then uid=dw_1.getitemstring(1,"usr_id") dw_1.scrolltorow(1) dw_1.selectrow(1,true) dw_1.setfocus() dw_2.retrieve(uid) //dw_2显示出第一个用户的不可选菜单项 dw_3.retrieve(uid) //dw_3显示出第一个用户的可选菜单项 end if dw_1的clicked事件中输入下列script: if row >0 then uid=dw_1.getitemstring(row,"usr_id") dw_2.retrieve(uid) dw_3.retrieve(uid) end if dw_1的rowfocuschanged事件中输入下列script: long rows,r rows=getrow() r=dw_1.rowcount() do while r >0 dw_1.selectrow(r,false) r=r -1 loop dw_1.selectrow(rows,true) //被选中的行反显 dw_2的doubleclicked事件中输入下列script: long rows string menu_id,m_id,userid rows=dw_2.getrow() menu_id=dw_2.getitemstring(rows,"menu_id") if mid(menu_id,2,4)="0000" then //如果当前双击的是一级菜单项 insert into menu_right(usr_id, menu_id) values(:uid, :menu_id); //把当前一级菜单项使用权赋给用户uid else if mid(menu_id,3,3)="000" then //如果当前双击的是二级菜单项 insert into menu_right(usr_id, menu_id) values(:uid, :menu_id); //把当前二级菜单项的使用权赋给用户uid m_id=mid(menu_id,1,1)+"0000" //当前二级菜单项所属的一级菜单项编号 //定义光标c1 declare c1 cursor for select usr_id from menu_right where usr_id=:uid and menu_id=:m_id;//光标对应的select语句 open c1; //打开光标,执行对应的SQL SELECT语句 fetch c1 into :userid; //判断uid是否具有当前 二级菜单项所属一级菜单项的使用权 if sqlca.sqlcode=100 then //如果uid不具有当前 二级菜单项所属一级菜单项的使用权 insert into menu_right(usr_id, menu_id) values(:uid, :m_id);//把当前二级菜单项所属的一级 菜单项的使用权赋给用户uid end if close c1; else //如果当前双击的是三级菜单项 insert into menu_right (usr_id, menu_id) values(:uid, :menu_id);//把当前三级菜单项的使用权赋给用户uid m_id=mid(menu_id,1,2)+"000"//当前 三级菜单项所属的二级菜单项的编号 //定义光标c2 declare c2 cursor for select usr_id from menu_right where usr_id=:uid and menu_id=:m_id;//光标对应的SELECT语句 open c2; //打开光标,执行对应的SQL SELECT语句 fetch c2 into :userid; //判断uid是否具有当前 三级菜单项所属的二级菜单项的使用权 if sqlca.sqlcode=100 then //如果uid不具有当前 三级菜单项所属的二级菜单项的使用权 insert into menu_right(usr_id, menu_id) values(:uid, :m_id); //把当前三级菜单项所属的 二级菜单项的使用权赋给用户uid end if close c2; m_id=mid(menu_id,1,1)+"0000" //当前三级菜单项所属 二级菜单项所属的一级菜单项的编号 //定义光标c3 declare c3 cursor for select usr_id from menu_right where usr_id=:uid and menu_id=:m_id; //光标对应的SELECT语句 open c3; //打开光标,执行对应的SQL SELECT语句 fetch c3 into :userid; //判断uid是否具有当前三 级菜单项所属二级菜单项所属的一级菜单项的使用权 if sqlca.sqlcode=100 then //如果uid不具有当前 三级菜单项所属二级菜单项所属的一级菜单项的使用权 insert into menu_right(usr_id, menu_id) values(:uid, :m_id); //把当前三级菜单项所属二 级菜单项所属的一级菜单项的使用权赋给用户uid end if end if dw_3.retrieve(uid) dw_2.retrieve(uid)

dw_3的doubleclicked事件中输入下列script: int rows string menu_id,m_sub rows=dw_3.getrow() menu_id=dw_3.getitemstring(rows,"menu_id") if mid(menu_id,2,4)="0000" then //如果双击的是一级菜单项 m_sub=mid(menu_id,1,1) delete from menu_right where substring(menu_id,1,1)=:m_sub and trim(menu_right.usr_id)=trim(:uid);// 删除当前一级菜单项及其所有的下拉菜单项 else if mid(menu_id,3,3)="000" then //如果双击的是二级菜单项 m_sub=mid(menu_id,1,2) delete from menu_right where substring(menu_id,1,2)=:m_sub and trim(menu_right.usr_id)=trim(:uid); //删除当前二级菜单项及其所有的下拉菜单项 else //如果双击的是三级菜单项 DELETE FROM menu_right WHERE ( menu_right.usr_id = :uid ) AND ( trim(menu_right.menu_id) = trim(:menu_id) ); //删除当前三级菜单项 end if end if dw_2.retrieve(uid) dw_3.retrieve(uid)


 

---- 7. 创 建MDI 类 型的 系 统 主 窗 口win_asysmain_mdi:


 

---- 连 接MDI 风 格 的系 统 主 菜 单, 在win_asysmain_mdi 的open 事 件 中, 输 入 下 列script:


 

---- long a


 

---- a=backcolor


 

---- if trim(yhh)='super' then //yhh 为 全 局 变 量, 是 用 户 登 录 时 录 入 的 用 户 号f_get_menu(win_asysmain_mdi.menuid)// 如 果 是 系 统 管 理 员 进 入 系 统, 则 调 用 自 定 义 函 数f_get_menu 把 主 菜 单 所 有 信 息 存 入menu_item 表 中else // 如 果 是 普 通 用户 进 入 系 统f_test_menu(win_asysmain_mdi.menuid,yhh)// 调 用 自 定 义 函 数f_test_menu 把 用 户 不 可 选 菜 单 项visible 属 性 设 为false


 

---- end if


 

---- 8. 创 建 用 户 登录 窗 口( 略):


 

---- 用 户 登 录 成 功后, 打 开 系 统 主 窗 口win_asysmain_mdi。


 

---- 9. 上 述 程 序 使用 说 明:


 

---- 用 户 登 录 时,系 统 判 断 如 果 用 户 号 合 法, 输 入 口 令 正 确, 则 进 入 系统 主 窗 口, 如 果 当 前 用 户 号 为“super”( 系 统 管 理 员), 则把 主 菜 单 所 有 信 息 存 入menu_item 表 中, 系 统 管 理 员 运 行主 菜 单 上 “ 权 限 管 理” 选 项, 进 入 权 限 管 理 窗 口,在“ 用 户 管 理” 模 块 中 设 定 的 所 有 用 户 名 显 示 在 授 权窗 口win_asyspermit 的 数 据 窗 win_asyspermit. dw_1 中, 用 鼠 标 双 击 某用 户 名, 则 此 用 户 不 可 选 菜 单 项 显 示 在 win_asyspermit. dw_2 中 , 此 用 户 可 选 菜 单 项 显 示 在win_asyspermit. dw_3 中, 如 果 是 第一 次 为 此 用 户 设 定 权 限, 则“ 不 可 选 菜 单 项” 中 显 示系 统 主 菜 单 所 有 项。 在“ 不 可 选 菜 单 项”(win_asyspermit. dw_2) 中 双 击 某 菜 单 项, 则 此 菜 单 项 从“ 不 可 选 菜 单项”(win_asyspermit. dw_2) 中 消 失, 并 添 加 到“ 可 选 菜 单项”(win_asyspermit. dw_3) 中。 同 样, 在“ 可 选 菜 单 项”(win_asyspermit. dw_3) 中 双 击 某 菜 单 项, 则 此 菜 单 项 从“ 可 选 菜 单项”(win_asyspermit. dw_3) 中 消 失, 并 添 加 到“ 不 可 选 菜 单项”(win_asyspermit. dw_2) 中。 这 样, 管 理 员 便 可 为 各 个 普 通用 户 赋 权 限。


 

---- 注 意: 如 果 把某 下 级 菜 单 项 赋 给 用 户, 则 其 上 级 菜 单 项 被 系 统 自 动赋 给 用 户; 如 果 把 某 用 户 可 选 菜 单 项 取 消, 则 系 统 自动 取 消 用 户 对 此 菜 单 项 的 所 有 下 级 菜 单 项 的 使 用 权。系 统 管 理 员 应 把“ 用 户 管 理”、“ 权 限 管 理” 等 系 统 管理 子 模 块 设 为 普 通 用 户“ 不 可 选 菜 单 项”。


 

---- 如 果 当 前 用 户号 不 是“super”, 而 是 普 通 用 户, 则 只 显 示 该 用 户 可 选 菜单 项, 该 用 户 只 能 运 行 相 应 模 块。


 

---- 10. 附 注:


 

---- 创 建 授 权 窗 口win_asyspermit 时, 可 以 用lb_1、lb_2、lb_3 取 代dw_1、dw_2、dw_3, 在script 语 句 中可 定 义 光 标, 把 表 中 某 列 内 容 逐 条 取 出, 用 函 数listboxname.AddItem(item) 增 加 到 列 表 框 中, 还 可 用 函 数 listboxname.Reset() 清 除 列 表 框中 所 有 项。 详 细script 在 此 不 再 赘 述。


 

          11. 上 述 程 序 具 有 很 强 的 实 用 性, 在PowerBuilder5.0 环 境 下 调 试通 过。

 
上一页 WanJuanShu.COM 下一页
WANJUANSHU.COM 万卷书