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 &RecsOut, int Options, const WideString: CommandText, OleVarian </P>
<P>t &Params, OleVariant: &OwnerData, OleVariant &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 &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->Exported = FLogin; </P>
<P> } </P>
<P>} </P>
<P>//--------------------------------------------------------------------------- </P>
<P>STDMETHODIMP TLoginServerImpl::Login() </P>
<P>{ </P>
<P> m_DataModule->Login = true; </P>
<P> return S_OK; </P>
<P>} </P>
<P>//--------------------------------------------------------------------------- </P>
<P>STDMETHODIMP TLoginServerImpl::Logout() </P>
<P>{ </P>
<P> m_DataModule->Login = false; </P>
<P> return S_FALSE; </P>
<P>} </P>
<P>//--------------------------------------------------------------------------- </P>
<P>bool __fastcall TLoginServer::IsLogin(OleVariant &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->Connection->AppServer); </P>
<P> ILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer; </P>
<P> dispLoginServer.Login(); </P>
<P> DM->cdsAnimals->Open(); </P>
<P>实现注册,并且打开相应数据集…… </P>
<P> </P>
<P>因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对 </P>
<P>绝大多数程序应该足以……:)</P>
页:
[1]