权限设计
基本上解释两个问题即可解释权限的运行逻辑:(1)何时触发权限检查(2)触发哪些权限检查(3)为了实现前两个逻辑而设计的逻辑。
(1)何时触发权限检查:在做界面设计,如果此设计属于“点击”且需要判断是否有权点击时,“检查权限”打上勾触发权限检查。这类设计主要有三类:菜单的点击、工具按钮的点击,界面按钮的点击。
(2)触发哪些权限检查:完成第一步设计后,通过菜单“编辑”--“权限配置文件”可以自动提取当前界面需要做权限检查的动作(并自动生成权限配置文件,在代码编译时自动生成权限代码,这个机制由底层完成),此时可以给每个动作分配权限参数,指令点击动作做哪些检查。比如成本中心主数据的查询操作,要求检查用户是否有成本范围和公司代码的权限。
“执行:检查输入值”:指权限检查的执行者(比如菜单、工具按钮、界面按钮)执行本身要求的权限检查。比如“显示”成本中心主数据的菜单,分配了权限参数P_CONCOD和P_COMCOD,那么点击此菜单时,自动检查用户是否有这两个参数的权限。这里有两头比较,用户分配的权限(后点介绍)和当前界面的参数值。当前界面的参数值由“参数值搜索于”的设置确定,可以输入固定值,可以输入SQL语句动态确定(比如根据输入的成本中心编码取得其所属公司),可以从系统参数(系统运行环境变量)确定,也可以从当前界面按数据源和值字段自动搜索。
“要求:检查输入值”:指界面字段本身不会触发权限检查,但又要求对此字段的输入值检查权限。比如查询界面的“工厂”字段,其自身不会触发权限检查,但查询的结果要求限定有权限的工厂数据才能出现,此时此控件要打上这个勾。当权限检查的执行者,在完成其自身的权限检查后,自动附带执行当前界面“要求:检查输入值”打上勾的字段输入值是否有权限。
(3)为了实现前两个逻辑而设计的逻辑
(3.1)维护权限参数,指明权限检查的具体点
实现此功能的业务代码
public class AU0002
{
private string FileName = "";
private EAS.Controls.TreeNode SelNode=null;
public void AuthPara_SizeChanged(Form sender, Event e)
{
Rectangle Client=ClientRectangle;
View1.Height=Client.Height-15;
}
public void AuthPara_Load(Form sender, Event e)
{
string FilePath=EAS.Comm.ServerDir;
FileName=FilePath + "\\SysAdmin\\AuthPro\\AuthPro.eas";
View1.LoadEas(FileName,"AuthPro");
}
public void View1_AfterSelectChanged(TreeView sender, Event e)
{
SelNode = null;
EAS.Controls.TreeNode Node=View1.SelectedNode;
if(Node.KeyCode1!="ParamID") return;
SelNode=Node;
tbName.Text=Node.KeyCode;
tbText.Text=Node.Text;
tbSource.Text=Node.KeyCode2;
tbField.Text=Node.KeyCode3;
tbSysPara.Text=Node.KeyCode4;
tbHelpID.Text=Node.KeyCode5;
Box1.ReadOnly=true;
}
public void AuthPara_MenuItemClick(Form sender, ItemClickEvent e)
{
switch(e.KeyCode)
{
case "New":
NewData();
break;
case "Edit":
EditData();
break;
case "Delete":
DeleteData();
break;
case "Save":
SaveData();
break;
}
AuthMode = e.Item.AuthMode;
}
private void NewData()
{
//EAS.Controls.TreeNode Node=View1.SelectedNode
//if(Node==null) return;
//if(Node.KeyCode1!="Folder")
// return;
Box1.Clear(true);
Box1.ReadOnly=false;
SelNode=null;
}
private void EditData()
{
if(SelNode==null)
{
string Message="未选择要编辑的权限参数";
EAS.Comm.ShowMessage("删除数据",Message,AnswerStyle.OKOnly);
return;
}
Box1.ReadOnly=false;
}
private void DeleteData()
{
string Message="未选择要删除的权限参数";
if(SelNode==null)
{
EAS.Comm.ShowMessage("删除数据",Message,AnswerStyle.OKOnly);
return;
}
tbName.Text=tbName.Text.Trim();
if(tbName.Text=="")
{
EAS.Comm.ShowMessage("删除数据",Message,AnswerStyle.OKOnly);
return;
}
Message="确实要删除权限参数“"+tbName.Text + "”吗?";
AnswerResult Result=EAS.Comm.ShowMessage("删除数据",Message,AnswerStyle.YesNo);
if(Result==AnswerResult.No) return;
View1.Delete(SelNode,true);
View1.SaveEas(FileName,"eas","AuthPro");
SelNode=null;
Box1.Clear(false);
EAS.Comm.ShowMessage(this,"数据已删除",MessageType.Normal);
}
private void SaveData()
{
if(!CheckData()) return;
if(AuthMode==AuthMode.New)
{
EAS.Controls.TreeNode Node=View1.SelectedNode;
bool Result = true;
if(Node==null) Result=false;
if(Result && Node.KeyCode1!="Folder")
Result=false;
if(Result && Node==View1.Root) //定位在模块上,且不能为ROOT
Result=false;
if(!Result)
{
string Message="请选择权限参数所属模块";
EAS.Comm.ShowMessage("保存数据",Message,AnswerStyle.OKOnly);
return;
}
CreateNode();
}
else
{
if(!IsModified())
{
string Message="没有权限参数被修改,无需更新";
EAS.Comm.ShowMessage("保存数据",Message,AnswerStyle.OKOnly);
return;
}
SelNode.KeyCode=tbName.Text;
SelNode.Text=tbText.Text;
SelNode.KeyCode2=tbSource.Text;
SelNode.KeyCode3=tbField.Text;
SelNode.KeyCode4=tbSysPara.Text;
SelNode.KeyCode5=tbHelpID.Text;
}
View1.Update();
View1.SaveEas(FileName,"eas","AuthPro");
Box1.ReadOnly=true;
EAS.Comm.ShowMessage(this,"数据已保存",MessageType.Normal);
}
private bool CheckData()
{
if(tbName.Text.Trim()=="")
return false;
if(tbText.Text.Trim()=="")
return false;
return true;
}
private bool IsModified()
{
if(SelNode==null) return false;
if(tbName.Modified || tbText.Modified || tbSource.Modified ||
tbField.Modified || tbSysPara.Modified)
return true;
return false;
}
private void CreateNode()
{
EAS.Controls.TreeNode Parent = View1.SelectedNode;
if(Parent==View1.Root) return;
if(Parent.KeyCode1!="Folder") return;
EAS.Controls.TreeNode Child = new EAS.Controls.TreeNode();
Child.KeyCode=tbName.Text;
Child.Text=tbText.Text;
Child.KeyCode2=tbSource.Text;
Child.KeyCode3=tbField.Text;
Child.KeyCode4=tbSysPara.Text;
Child.KeyCode5=tbHelpID.Text;
Child.KeyCode1="ParamID";
Child.DisplayAll=true;
View1.Add(Child,Parent,false);
}
}
(3.2)角色维护:即定义角色拥有的具体参数值,其值由下面的颗粒度确定:用户+事务代码+动作的KEYCOD+权限参数。比如用户A可以查询成本范围1000、2000的成本中心主数据,但其只能新增成本范围1000的成本中心主数据。在输入事务码时,系统自动提取界面设计时分配的权限配置文件并解析。
(3.3)维护岗位角色
(3.4)用户维护
业务代码
using \SysAdmin\API\UserAuth\Users\IFX002;
public class X00002
{
public void X00002_Load(Form sender, Event e)
{
string FileName = SourceFile;
if(FileName=="")
{
Enabled=false;
EAS.Comm.ShowMessage(this,"无效的数据结构文件",MessageType.Error);
return;
}
XarrayTree.LoadSchema(FileName); //加载数据源结构
}
public void X00002_MenuItemClick(Form sender, ItemClickEvent e)
{
switch(e.KeyCode)
{
case "Load":
LoadData();
break;
case "New":
NewData();
break;
case "Edit":
EditData();
break;
case "Save":
SaveData();
break;
case "Delete":
DeleteData();
break;
}
AuthMode = e.Item.AuthMode;
}
private bool LoadData()
{
if(!CheckData()) return false;
IFX002 API = new IFX002(XarrayTree);
if(!API.Exists(USRCOD.Text))
{ //用户没有创建
EAS.ResultInfo.Throw(this);
return false;
}
EAS.ResultInfo.Clear(this); //重置消息清单
List<string> Filters=GetFilters();
XarrayTree.LoadData(Filters,1); //根据过滤条件加载第一数据源及下级
if(!EAS.ResultInfo.Check()) //检查是否存在错误消息
{
EAS.ResultInfo.Throw(this); //抛出消息清单
return false;
}
XarrayAll(); //把取回的数据显示到界面
ReadOnly=true;
USRCOD.ReadOnly=false;
return true;
}
private bool CheckData()
{ //显示数据时必须的检查
EAS.ResultInfo.Clear(this);
if(USRCOD.Text == "")
EAS.ResultInfo.Add("","用户名不能为空",MessageType.Error,"");
if(!EAS.ResultInfo.Check())
{
EAS.ResultInfo.Throw(this);
return false;
}
return true;
}
private List<string> GetFilters()
{ //根据界面数据生成第一级数据源的过滤条件
List<string> Filters=new List<string>();
string FilterSQL="USRCOD='" + USRCOD.Text + "'";
Filters.Add(FilterSQL);
return Filters;
}
private void NewData()
{
EAS.ResultInfo.Clear(this);
ReadOnly=false; //界面设置为可编辑
Clear(true); //清空界面上的所有数据
if(!XarrayTree.Clear()) //清空数据源的所有层级的数据
{
EAS.ResultInfo.Throw(this);
return;
}
XarrayTree.New("X00002",1); //数据源增加一空行
if(!EAS.ResultInfo.Check())
{ //增加空行失败
EAS.ResultInfo.Throw(this);
return;
}
}
private void EditData()
{
if(!LoadData()) return;
ReadOnly=false;
USRCOD.ReadOnly=true;
}
private void DeleteData()
{
EAS.ResultInfo.Clear(this); //重置消息清单
if(!CheckData()) return;
IFX002 API = new IFX002(XarrayTree);
if(!API.Exists(USRCOD.Text))
{ //用户没有创建
EAS.ResultInfo.Throw(this);
return;
}
if(!API.Check(USRCOD.Text)) //删除前的检查
{
EAS.ResultInfo.Throw(this);
return;
}
List<string> Filters = GetFilters();
XarrayTree.LoadData(Filters); //加载删除的数据
XarrayAll();
string Message = "确实要删除用户“"+USRCOD.Text+"”吗?";
AnswerResult Result = EAS.Comm.ShowMessage("删除数据",Message,AnswerStyle.YesNo);
if(Result==AnswerResult.No)
return;
if(API.Delete())
{
Clear(false); //清空界面数据
ReadOnly = true;
USRCOD.ReadOnly=false;
EAS.Comm.ShowMessage(this, "数据已被删除", MessageType.Normal);
}
else
EAS.ResultInfo.Throw(this);
}
private void SaveData()
{
if(AuthMode == AuthMode.Display || AuthMode == AuthMode.None)
{
EAS.Comm.ShowMessage(this,"非编辑状态,无数据更新",MessageType.Error);
return;
}
if(AuthMode==AuthMode.New) //新增时检查用户是否已存在
{
Xarray Array = new Xarray();
string FilterSQL = "USRCOD='" + USRCOD.Text + "'";
if(Array.LoadData("X00002",FilterSQL))
{
string Message = "用户“"+USRCOD.Text+"”已存在";
EAS.Comm.ShowMessage(this,Message,MessageType.Error);
return;
}
}
if(!Check()) return; //检查必输字段是否已输
if(AuthMode!=AuthMode.New)
XarrayTree.Clone("X00002"); //保存旧数据
UpdateAll(); //把界面数据更新到数据源
EAS.ResultInfo.Clear(this); //重置消息清单
IFX002 API = new IFX002(XarrayTree); //开始调用API
if(API.SaveData())
{
AuthMode=AuthMode.None; //重置操作状态
ReadOnly=true; //字段变为只读
USRCOD.ReadOnly=false;
XarrayTree.AcceptChanges(); //所有数据置为未更改状态
EAS.Comm.ShowMessage(this, "数据保存成功", MessageType.Normal);
}
else
EAS.ResultInfo.Throw(this);
}
}
(3.5)给用户分配岗位角色
业务代码
public class AU0006
{
public void AU0006_Load(Form sender, Event e)
{
string FileName = SourceFile;
if(FileName=="")
{
Enabled=false;
EAS.Comm.ShowMessage(this,"无效的数据结构文件",MessageType.Error);
return;
}
XarrayTree.LoadSchema(FileName);
}
public void USRCOD_Enter(TextBox sender, Event e)
{ //回车时显示关联文本
if(USRCOD.Text=="")
{
USRCOD.SetBrother(""); //清空关联文本
return;
}
Xarray Array = new Xarray();
string FilterSQL="USRCOD='" + USRCOD.Text + "'";
string Text=Array.GetValue("X00002","USRNAM",FilterSQL);
USRCOD.SetBrother(Text);
}
public void P00001_MenuItemClick(Form sender, ItemClickEvent e)
{
switch(e.KeyCode)
{
case "Load":
LoadData();
break;
case "New":
NewData();
break;
case "Edit":
EditData();
break;
case "Save":
SaveData();
break;
case "Delete":
DelData();
break;
case "NewRows":
NewRows();
break;
case "DelRow":
DelRow();
break;
}
AuthMode = e.Item.AuthMode;
}
private bool LoadData()
{
if(!CheckData())
{
EAS.ResultInfo.Throw(this);
return false;
}
EAS.ResultInfo.Clear(this); //重置消息清单
List<string> Filters=GetFilters();
XarrayTree.LoadData(Filters);
if(!EAS.ResultInfo.Check()) //检查是否存在错误消息
{
EAS.ResultInfo.Throw(this); //抛出消息清单
return false;
}
Box1.XarrayAll(); //把取回的数据显示到界面
ReadOnly=true;
USRCOD.ReadOnly=false;
return true;
}
private bool CheckData()
{ //显示数据时必须的检查
EAS.ResultInfo.Clear(this);
if(USRCOD.Text == "")
{
EAS.ResultInfo.Add("","用户不能为空",MessageType.Error,"");
return false;
}
string UsrCod = USRCOD.Text.Trim();
Xarray Array = new Xarray();
Array.LoadData("SELECT USRNAM FROM X00002 WHERE USRCOD ='" + UsrCod + "'");
if (Array.Rows.Count(XarrayType.Edited) == 0)
{
EAS.ResultInfo.Add("", "无效的用户", MessageType.Error, "");
return false;
}
return true;
}
private List<string> GetFilters()
{
List<string> Filters=new List<string>();
string FilterSQL="USRCOD='" + USRCOD.Text + "'";
Filters.Add(FilterSQL);
return Filters;
}
private void NewData()
{
EAS.ResultInfo.Clear(this);
ReadOnly=false; //界面设置为可编辑
Clear(true); //清空界面上的所有数据
if(!XarrayTree.Clear()) //清空数据源的所有层级的数据
{
EAS.ResultInfo.Throw(this);
return;
}
XarrayTree.New("V00007",10);
Box1.XarrayAll();
}
private void EditData()
{
if(!LoadData()) return;
XarrayTree.New("V00007",10);
Box1.XarrayAll();
USRCOD.ReadOnly=true;
Box1.ReadOnly=false;
}
private void SaveData()
{
if(!CheckData())
{
EAS.ResultInfo.Throw(this);
return;
}
EAS.ResultInfo.Clear(this);
Xarray Array=XarrayTree.GetXarray("V00007");
int Count=Array.Rows.Count(XarrayType.Edited);
for (int Index = 0; Index < Count; Index++)
{ //把用户推送入数据源
if(Array.IsEmpty(Index)) break;
Array.SetValue(USRCOD.Text,Index,"USRCOD",false);
string Name=Array.GetValue(Index,"AUCOD2");
Name=GetName(Name);
Array.SetValue(Name,Index,"AUCOD0",false);
}
XarrayTree.Submit();
if(EAS.ResultInfo.Check())
{
EAS.Comm.ShowMessage(this, "数据保存成功", MessageType.Normal);
Box1.XarrayAll();
}
else
EAS.ResultInfo.Throw(this);
}
public void Grid1_BeforeUpdate(EditGrid sender, CancelEvent e)
{
Xarray Array = XarrayTree.GetXarray("V00007");
int Count=Array.Rows.Count(XarrayType.Edited);
for (int Index = 0; Index < Count; Index++)
{
if (Array.GetValue(Index, "AUCOD2") == e.NewValue)
{
e.Canceled = true;
EAS.ResultInfo.Throw(this,"角色“" + e.NewValue + "”已存在", MessageType.Error);
return;
}
}
string Name = GetName(e.NewValue);
Array = new Xarray();
Array.LoadData("AU0001", "AUCOD0='" + Name + "' AND AUTYP0='2'");
if (Array.Rows.Count(XarrayType.Edited) == 0)
{
e.Canceled = true;
EAS.ResultInfo.Throw(this, "无效的角色名称", MessageType.Error);
}
}
private string GetName(string Name)
{
Name = Name.Replace(":", "");
return Name;
}
public void Grid1_AfterUpdated(EditGrid sender, Event e)
{
string Name = GetName(e.Value);
Xarray Array = new Xarray();
string Text = Array.GetValue("AU001T", "NAME00", "AUCOD0='" + Name + "' AND LANG00='ZH'");
Array = XarrayTree.GetXarray("V00007");
Array.SetValue(Text, e.RowIndex, "NAME00",false);
Grid1.Update();
}
private void NewRows()
{
if (Grid1.ReadOnly) return;
XarrayTree.New("V00007",10);
Box1.XarrayAll();
}
private void DelRow()
{
if (Grid1.ReadOnly) return;
int RowIndex = Grid1.SelectedRowIndex;
string Name = XarrayTree.GetValue("V00007",RowIndex, "AUCOD2");
string Message = "确定要移除角色“" + Name + "”?";
AnswerResult Result = EAS.Comm.ShowMessage("移除数据", Message, AnswerStyle.YesNo);
if (Result == AnswerResult.No) return;
XarrayTree.Delete("V00007",RowIndex);
Box1.XarrayAll();
}
private void DelData()
{
if (!CheckData())
{
EAS.ResultInfo.Throw(this);
return;
}
if(!LoadData()) return;
string Message = "确定要删除用户“" + USRCOD.Text + "”分配的角色?";
AnswerResult Result = EAS.Comm.ShowMessage("删除数据", Message, AnswerStyle.YesNo);
if (Result == AnswerResult.No) return;
if(!XarrayTree.Delete("V00007"))
{
EAS.ResultInfo.Throw(this);
return;
}
XarrayTree.Submit();
if(EAS.ResultInfo.Check())
EAS.ResultInfo.Throw(this,"用户分配的角色已删除",MessageType.Normal);
else
EAS.ResultInfo.Throw(this);
Clear(false);
ReadOnly = true;
USRCOD.ReadOnly = false;
}
}
(3.6)在此之外还有一个大框架,发布程序时必须指定是显示、新增还是修改等。
下一篇:调试业务代码
上一篇:业务实现的基本逻辑