6 a5 p. N' i$ i+ z. D
前面hawkfly提到的在多层编程中,服务器端安全性验证的问题
: z8 w3 s/ z3 a在以socket方式实现MIDAS时尤为明显,DCOM/CORBA都有现成的
安全管理功能,而socket方式在这方面比较薄弱,没有现成的解决方案
( o. x# _0 A* O3 o# P现就我以前对MIDAS编程的理解,做一个简要的介绍,
% g) h, g; x( K以后有时间精力再详细举例说明
6 z; y. _3 l( B( s" I
win2k中dcom的安全级别有7种,其中
, F- N( d/ d! e m最低的“无”安全检查暂且不论
默认的“身份验证”服务方式几句话也说不清,
- Z- b& ~. V% v+ ^' c' I先放到一边,看看剩下的5种
( I1 {% g& b" z& d7 r
1.连接,仅对初始连接进行安全检查
因为tcp/ip是稳固的连接,因此每个连接,也就是每个RemoteDataModule
0 _- ^* W! K$ d, O, {实例检测一次即可,实现方法很多,这里简要介绍一种最简单的
/ ?1 i' J5 L: `& k可以在服务器端的TypeLibrary里面为你的服务器接口增加若干个方法,如
1 K C) d4 h& Qinterface ILoginServer: IAppServer
$ n" @) c7 T" l{
0 s( ` t9 S% [[
id(0x00000001)
. G: L9 z Z: x# {' x: Y]
HRESULT _stdcall Login( void );
9 L$ P* y* e0 J5 v [: q2 Q[
% q r* [8 i) i, G& Q: \" `id(0x00000002)
# V6 @. s' p$ B' X; ~4 n]
7 X& Z( k, m1 h8 x- PHRESULT _stdcall Logout( void );
/ T6 ?2 }0 [, q- i$ q ^$ b};
在方法中实现你的客户身份校验,而在校验之前,通过把RDM上所有的TDataSetProvider
的Exported属性关掉即可让客户端无法看到服务器端的provider
因为客户端实际上是在连接服务器成功后通过服务器之IAppServer接口访问
8 x/ o7 Y$ i+ t* u所有的Provider,如IAppServer::AS_GetProviderNames可以取得
9 t) _, C8 a9 M9 G0 \. `服务器端所有exported的IProvider接口名称,而所有数据的取得、修改
" c' h: |2 x0 w! i都是通过相应的ProviderName来指定的,如
$ n* a% Z; e' t b7 }" i9 ~! ^virtual HRESULT __safecall AS_GetRecords(const WideString: ProviderName, in
- z) _4 g; |: u/ f1 st Count, int &RecsOut, int Options, const WideString: CommandText, OleVarian
# J* d( _$ `% Lt &
arams, OleVariant: &OwnerData, OleVariant &GetRecords_result) = 0 ;
取得数据方法的第一个参数就是你需要操作的数据集名称……
+ L( r. a* z+ b$ I$ R0 b# v1 Q7 w如果你把服务器RDM上所有的TDataSetProvider::Exported关掉,
4 w, S0 {. J% M7 c4 R2 q+ X3 t5 L则客户端看不到任何Provider,也无法通过其ProviderName取得数据
% c! v4 E E, U例如我在服务器端的RDM类中加入
1 g5 a$ ~+ s6 i2 b& Jclass TLoginServer : public TCRemoteDataModule
{
...
private: // User declarations
6 N) p7 e1 \2 ^# E3 [" Y) nbool FLogin;
- i) h5 F+ A8 a3 S! ~5 vvoid __fastcall SetLogin(bool value);
bool __fastcall IsLogin(OleVariant &OwnerData);
& l1 e' X/ ^2 {" C- J...
__published:
__property bool Login = { read = FLogin, write = SetLogin };
};
在RDM实现类中
% s& L+ | ~$ X7 i6 _class ATL_NO_VTABLE TLoginServerImpl: 。。。
/ P4 j8 h7 t5 H1 F% B' \{
// ILoginServer
protected:
3 M6 r% N: V7 B. o# ^STDMETHOD(Login());
STDMETHOD(Logout());
- _- b7 }" Z, D0 f7 c: B* Q};
: h! C% M3 K5 W! D* U然后简单实现之
6 U. V* d% U) Z+ P__fastcall TLoginServer::TLoginServer(TComponent* Owner)
/ \! q0 g) [9 S: B) m: TCRemoteDataModule(Owner), FLogin(false)
{
* J0 W; } K; j( V$ m' I; n& m}
9 a% O; t8 |: H//---------------------------------------------------------------------------
1 o% ^4 v2 l' K$ kvoid __fastcall TLoginServer::SetLogin(bool value)
8 g, \3 [" x5 u$ y& l6 A{
if(FLogin != value)
; ^6 ^2 ]) s" w, |{
3 s: Y/ f5 M& P4 h& t' ?2 qFLogin = value;
& c/ t( Q; f3 X* fdspAnimals->Exported = FLogin;
}
}
//---------------------------------------------------------------------------
STDMETHODIMP TLoginServerImpl:
ogin()
{
m_DataModule->Login = true;
7 j7 J3 f& j* t, freturn S_OK;
}
1 u) ~( a: h: a, y+ R//---------------------------------------------------------------------------
STDMETHODIMP TLoginServerImpl:
ogout()
{
m_DataModule->Login = false;
return S_FALSE;
}
# A, X2 n; y% j: B: F: x. T! [" ?//---------------------------------------------------------------------------
bool __fastcall TLoginServer::IsLogin(OleVariant &OwnerData)
) X# X) f: u* p0 m0 P{
7 {( l4 @( O# Q* r% v+ |: dreturn FLogin;
N9 I! G8 L2 | _2 r}
easy
这样除非你的客户端成功调用Login方法,否则他是无法使用
dspAnimals这个数据集Provider的,成功调用后手工打开的数据集使用完全相同
! T" H3 {1 U: n
比如客户端可以用如下代码
IDispatch *dispAppServer = (IDispatch*)(DM->Connection->AppServer);
9 A, r E2 x2 D' H/ i3 KILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer;
dispLoginServer.Login();
DM->cdsAnimals->Open();
实现注册,并且打开相应数据集……
因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对
0 j$ ]5 E0 L2 h1 i* q+ j& p4 Z绝大多数程序应该足以……
| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) | Powered by Discuz! X2.5 |