|
3 K! y, ~( i3 j' q$ ]- L) P
前面hawkfly提到的在多层编程中,服务器端安全性验证的问题
+ C# u3 ~1 X# r: w' W在以socket方式实现MIDAS时尤为明显,DCOM/CORBA都有现成的 R/ r5 Z- v" D8 A" Y
安全管理功能,而socket方式在这方面比较薄弱,没有现成的解决方案 ! r6 _, W. n/ }. E+ n/ t, ~
现就我以前对MIDAS编程的理解,做一个简要的介绍,
3 n2 y& p) c6 K: s' h以后有时间精力再详细举例说明 1 T9 \2 k. [5 `
: Z( {- r$ b: z( n& ~- U$ l
win2k中dcom的安全级别有7种,其中
$ W: f& H' K* G$ m+ m( |& }$ @+ u最低的“无”安全检查暂且不论 $ J% D2 Q2 G& q/ c
默认的“身份验证”服务方式几句话也说不清, : Y* x& s( c) _
先放到一边,看看剩下的5种 0 W! a! b S2 ~ h
7 j$ Y* E0 g5 _: q1.连接,仅对初始连接进行安全检查 . ^7 C. ?7 D, U# u5 F
3 U$ A$ |/ ]* N4 F; V6 q" y 因为tcp/ip是稳固的连接,因此每个连接,也就是每个RemoteDataModule 7 z1 O/ K9 B5 w$ N0 x2 p& y
实例检测一次即可,实现方法很多,这里简要介绍一种最简单的
& K" C3 }: s6 ^2 F! ~ 可以在服务器端的TypeLibrary里面为你的服务器接口增加若干个方法,如
7 P( |! ~5 U3 O' N* U interface ILoginServer: IAppServer
; X. {3 K; D2 [# W" j2 c6 a8 [{ : F9 h w& W1 R6 p0 M# e
[ 0 F. N& m- U' s" U; v
id(0x00000001) " N" {2 m+ l4 k2 S7 [0 w5 W8 l* a
] 9 N2 W% ?5 b: a
HRESULT _stdcall Login( void );
5 N( ~% I' e; A1 R [
) |3 w, o: Q6 A1 L5 i; ^ id(0x00000002) 3 K! @ d4 z' T4 n! m; P
] ; i3 Z/ s) s" d9 c
HRESULT _stdcall Logout( void ); ' ]0 c+ ` \$ W5 B# M7 u* a4 Y
};
* q1 y8 |% S" ]3 I- c! z 在方法中实现你的客户身份校验,而在校验之前,通过把RDM上所有的TDataSetProvider : v" m9 P$ O- @4 X2 V& X5 _5 m
的Exported属性关掉即可让客户端无法看到服务器端的provider ' q! t/ ?" `; q( C4 D7 U" e
因为客户端实际上是在连接服务器成功后通过服务器之IAppServer接口访问 , [0 w8 o7 _3 {7 ]$ F
所有的Provider,如IAppServer::AS_GetProviderNames可以取得
* h) {- [. d! w* o 服务器端所有exported的IProvider接口名称,而所有数据的取得、修改
% s4 T: k6 U/ j 都是通过相应的ProviderName来指定的,如 % \2 L) m( i/ ]4 D$ |2 f; }
virtual HRESULT __safecall AS_GetRecords(const WideString: ProviderName, in
( |% e$ z# w W; K1 ?, ~( ot Count, int &RecsOut, int Options, const WideString: CommandText, OleVarian 5 w) V2 \$ K; G0 {: L- ~0 k
t & arams, OleVariant: &OwnerData, OleVariant &GetRecords_result) = 0 ; 9 H5 W; c. l- J+ C
取得数据方法的第一个参数就是你需要操作的数据集名称…… . N- K2 q5 H. c# _ ]* |3 X
如果你把服务器RDM上所有的TDataSetProvider::Exported关掉,
1 }7 g# s0 \7 R# } 则客户端看不到任何Provider,也无法通过其ProviderName取得数据
4 ^3 k; b3 C/ w1 H9 J* Y" D 例如我在服务器端的RDM类中加入
1 d- [4 a) D' D4 Nclass TLoginServer : public TCRemoteDataModule ! N1 z% u4 U+ L; @
{
! F- l- Z& t2 U0 D- z8 L# P... ) d; t: S% _2 p: C
private: // User declarations + c- F* \9 c9 {' D9 b( P' e
bool FLogin;
/ \5 I0 e+ t0 L! V9 _% t void __fastcall SetLogin(bool value); " n" g3 R7 H4 X7 w4 }9 J, E
bool __fastcall IsLogin(OleVariant &OwnerData); + ]3 S5 W; F# V. q, |
... 9 ]* M# y, D# t# c2 V5 ~
__published:
5 u* C5 _* g4 K1 ?! M' e __property bool Login = { read = FLogin, write = SetLogin };
% ?. H; e/ I) i S3 {}; % F* L: E# Q$ j4 e) M8 ]) Y
在RDM实现类中
7 ]4 z) k$ W- w* l; E: fclass ATL_NO_VTABLE TLoginServerImpl: 。。。 6 D: \2 |0 M# C* K4 b
{ 5 Y2 o7 Z2 ?3 P3 z7 O
// ILoginServer 6 x$ w W. X7 U9 i8 b6 f
protected: 3 Q& k8 k# \% x8 _- k. h Z" B
STDMETHOD(Login());
1 J1 ~2 W+ @- f$ b* O- V( n; u STDMETHOD(Logout());
: o6 l4 j1 r% q7 D};
; S1 ~4 x, [ r0 R/ A* V然后简单实现之 ' d% K" M* R6 ?0 Q6 J
__fastcall TLoginServer::TLoginServer(TComponent* Owner)
5 _/ _9 y! A e2 G$ f8 q5 U : TCRemoteDataModule(Owner), FLogin(false)
c6 H7 B. E( ]) H* [+ \0 T{ 7 l8 g) n. g9 F# E
}
2 G$ R7 e4 }( j4 W//---------------------------------------------------------------------------
/ ?# h- e1 [6 mvoid __fastcall TLoginServer::SetLogin(bool value)
& s; h0 U6 G% z" ^4 _$ a7 J{ , Q9 j; r3 s% n1 ^' }9 D
if(FLogin != value)
H4 b/ Q5 W1 o/ V$ r6 g8 A% V O { 5 y* i2 @, w9 E' Y! ?' E$ v
FLogin = value;
" W, ?/ Q9 Q: G dspAnimals->Exported = FLogin;
. b. R" k* M0 U! f4 G }
4 Z0 g8 l) }8 N0 w5 g4 y}
( U& m; ?/ g6 {8 V2 T//---------------------------------------------------------------------------
0 D' O/ g0 m2 ?' w* ^3 dSTDMETHODIMP TLoginServerImpl: ogin()
9 B( S$ {3 X: v+ W7 `5 N{ " l. s |, N3 n$ [ G
m_DataModule->Login = true; ( w# ^& E& J! G* [2 h
return S_OK; + n( V+ |" X# l* f# H6 _0 B
}
. p5 q- l& q) R' Q! `//---------------------------------------------------------------------------
0 N, u, Q1 P p$ j7 oSTDMETHODIMP TLoginServerImpl: ogout() $ k2 W( J9 I3 e' L/ J6 ?
{ 7 R" B' \$ d& a5 x3 |
m_DataModule->Login = false; 6 K0 W1 ?; a- x; i3 E/ O
return S_FALSE;
7 g. Y! v9 ^ F} , \+ z- c" e+ y* I! k9 T
//---------------------------------------------------------------------------
+ ?" [, Q$ ^! n- rbool __fastcall TLoginServer::IsLogin(OleVariant &OwnerData)
# O r8 ]' P3 w1 B3 h{
' y8 ^" w, j0 Y5 Q% G1 c return FLogin;
8 \. Y1 a2 ~4 i$ ]} 9 N) O2 n4 a! T' {2 ]9 k0 e m
easy 这样除非你的客户端成功调用Login方法,否则他是无法使用 6 g; L6 [' Z$ a& }2 M
dspAnimals这个数据集Provider的,成功调用后手工打开的数据集使用完全相同 ) ]( T4 S' C. P: S5 s3 I: ]
& m2 U0 y! m6 `6 b
比如客户端可以用如下代码 % C: t' E! \' u7 f8 `3 R$ r
IDispatch *dispAppServer = (IDispatch*)(DM->Connection->AppServer); 4 h' ~; R. ~* [: k) t! D
ILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer;
' ~( b; T% d- _% ?6 R dispLoginServer.Login(); 6 V j5 W- e% H( i. d
DM->cdsAnimals->Open();
# }+ x6 F ^ n, }实现注册,并且打开相应数据集…… , _' p0 S1 N! @' j& e( C" f
' [4 Z0 s( ^* s) ?; {/ o0 G2 Z因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对
: s0 l# i1 k6 _ p6 N8 O. j- U/ v绝大多数程序应该足以…… |