韩冰 发表于 2005-1-26 01:08

socket连接多层程序安全性简述 - 连接

<P>  </P>
<P>前面hawkfly提到的在多层编程中,服务器端安全性验证的问题 </P>
<P>在以socket方式实现MIDAS时尤为明显,DCOM/CORBA都有现成的 </P>
<P>安全管理功能,而socket方式在这方面比较薄弱,没有现成的解决方案 </P>
<P>现就我以前对MIDAS编程的理解,做一个简要的介绍, </P>
<P>以后有时间精力再详细举例说明 :) </P>
<P>  </P>
<P>win2k中dcom的安全级别有7种,其中 </P>
<P>最低的“无”安全检查暂且不论 :) </P>
<P>默认的“身份验证”服务方式几句话也说不清, </P>
<P>先放到一边,看看剩下的5种 </P>
<P>  </P>
<P>1.连接,仅对初始连接进行安全检查 </P>
<P>  </P>
<P>  因为tcp/ip是稳固的连接,因此每个连接,也就是每个RemoteDataModule </P>
<P>  实例检测一次即可,实现方法很多,这里简要介绍一种最简单的 </P>
<P>  可以在服务器端的TypeLibrary里面为你的服务器接口增加若干个方法,如 </P>
<P> interface ILoginServer: IAppServer </P>
<P>{ </P>
<P>  [ </P>
<P>  id(0x00000001) </P>
<P>  ] </P>
<P>  HRESULT _stdcall Login( void ); </P>
<P>  [ </P>
<P>  id(0x00000002) </P>
<P>  ] </P>
<P>  HRESULT _stdcall Logout( void ); </P>
<P>}; </P>
<P>  在方法中实现你的客户身份校验,而在校验之前,通过把RDM上所有的TDataSetProvider </P>
<P>  的Exported属性关掉即可让客户端无法看到服务器端的provider </P>
<P>  因为客户端实际上是在连接服务器成功后通过服务器之IAppServer接口访问 </P>
<P>  所有的Provider,如IAppServer::AS_GetProviderNames可以取得 </P>
<P>  服务器端所有exported的IProvider接口名称,而所有数据的取得、修改 </P>
<P>  都是通过相应的ProviderName来指定的,如 </P>
<P>virtual HRESULT __safecall AS_GetRecords(const WideString: ProviderName, in </P>
<P>t Count, int &amp;RecsOut, int Options, const WideString: CommandText, OleVarian </P>
<P>t &amp;Params, OleVariant: &amp;OwnerData, OleVariant &amp;GetRecords_result) = 0 ; </P>
<P>  取得数据方法的第一个参数就是你需要操作的数据集名称…… </P>
<P>  如果你把服务器RDM上所有的TDataSetProvider::Exported关掉, </P>
<P>  则客户端看不到任何Provider,也无法通过其ProviderName取得数据 </P>
<P>  例如我在服务器端的RDM类中加入 </P>
<P>class TLoginServer : public TCRemoteDataModule </P>
<P>{ </P>
<P>... </P>
<P>private:      // User declarations </P>
<P>  bool FLogin; </P>
<P>  void __fastcall SetLogin(bool value); </P>
<P>  bool __fastcall IsLogin(OleVariant &amp;OwnerData); </P>
<P>... </P>
<P>__published: </P>
<P>  __property bool Login = { read = FLogin, write = SetLogin }; </P>
<P>}; </P>
<P>在RDM实现类中 </P>
<P>class ATL_NO_VTABLE TLoginServerImpl: 。。。 </P>
<P>{ </P>
<P>// ILoginServer </P>
<P>protected: </P>
<P>  STDMETHOD(Login()); </P>
<P>  STDMETHOD(Logout()); </P>
<P>}; </P>
<P>然后简单实现之 </P>
<P>__fastcall TLoginServer::TLoginServer(TComponent* Owner) </P>
<P> : TCRemoteDataModule(Owner), FLogin(false) </P>
<P>{ </P>
<P>} </P>
<P>//--------------------------------------------------------------------------- </P>
<P>void __fastcall TLoginServer::SetLogin(bool value) </P>
<P>{ </P>
<P>  if(FLogin != value) </P>
<P>  { </P>
<P>    FLogin = value; </P>
<P>    dspAnimals-&gt;Exported = FLogin; </P>
<P>  } </P>
<P>} </P>
<P>//--------------------------------------------------------------------------- </P>
<P>STDMETHODIMP TLoginServerImpl::Login() </P>
<P>{ </P>
<P>  m_DataModule-&gt;Login = true; </P>
<P>  return S_OK; </P>
<P>} </P>
<P>//--------------------------------------------------------------------------- </P>
<P>STDMETHODIMP TLoginServerImpl::Logout() </P>
<P>{ </P>
<P>  m_DataModule-&gt;Login = false; </P>
<P>  return S_FALSE; </P>
<P>} </P>
<P>//--------------------------------------------------------------------------- </P>
<P>bool __fastcall TLoginServer::IsLogin(OleVariant &amp;OwnerData) </P>
<P>{ </P>
<P>  return FLogin; </P>
<P>} </P>
<P>easy :) 这样除非你的客户端成功调用Login方法,否则他是无法使用 </P>
<P>dspAnimals这个数据集Provider的,成功调用后手工打开的数据集使用完全相同 </P>
<P>  </P>
<P>比如客户端可以用如下代码 </P>
<P>  IDispatch *dispAppServer = (IDispatch*)(DM-&gt;Connection-&gt;AppServer); </P>
<P>  ILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer; </P>
<P>  dispLoginServer.Login(); </P>
<P>  DM-&gt;cdsAnimals-&gt;Open(); </P>
<P>实现注册,并且打开相应数据集…… </P>
<P>  </P>
<P>因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对 </P>
<P>绝大多数程序应该足以……:)</P>
页: [1]
查看完整版本: socket连接多层程序安全性简述 - 连接