|
8 y' n7 t& _* F. ~+ h/ U. u+ D
前面hawkfly提到的在多层编程中,服务器端安全性验证的问题 ; @1 ]- _: b4 E: _
在以socket方式实现MIDAS时尤为明显,DCOM/CORBA都有现成的
6 t" ^! x, M+ U$ o6 a安全管理功能,而socket方式在这方面比较薄弱,没有现成的解决方案
" j$ i+ Z) A( n$ G' Z现就我以前对MIDAS编程的理解,做一个简要的介绍,
% o& a; W; S8 q9 w5 x以后有时间精力再详细举例说明 : D; s8 Z/ y; Q; \; U
3 v+ ^" ~; W C: ^. g5 w% t" |: T
win2k中dcom的安全级别有7种,其中 2 r& U* _& z# h3 Z w# z
最低的“无”安全检查暂且不论
8 f! K/ R0 L9 ~' y默认的“身份验证”服务方式几句话也说不清, 9 B4 p. x' R: T5 T
先放到一边,看看剩下的5种
4 V4 K9 ]4 u! e R5 [; O7 U4 D 5 Y ]2 W4 m" H: h% C/ `) ^; L
1.连接,仅对初始连接进行安全检查 8 f2 U2 R$ ?6 c* |% ?9 K; }
" v4 i- t0 p2 I: v" C0 c1 M
因为tcp/ip是稳固的连接,因此每个连接,也就是每个RemoteDataModule
1 N) q1 t) f' y/ F: X" ~ 实例检测一次即可,实现方法很多,这里简要介绍一种最简单的
+ |) }$ @- q7 Y: I 可以在服务器端的TypeLibrary里面为你的服务器接口增加若干个方法,如
5 R& E" ^3 c, E/ v interface ILoginServer: IAppServer 0 P6 Q6 t+ M Z+ I+ d0 X
{ , [) B3 N( Y( s3 {+ N$ k. `9 E
[ + {/ a' W. W! w# P& [
id(0x00000001) , m/ y6 O( a0 G! c/ } O/ ~4 V
]
; o9 x- d* C5 @+ a1 [: b HRESULT _stdcall Login( void );
% G h+ |) V, C [
- h: A8 x0 z. t id(0x00000002) 5 ?- d3 S8 k. Q2 F
] H& R" p* ?, l: ~7 d; @$ E9 T
HRESULT _stdcall Logout( void ); ; ?# l' a0 j4 B
}; & n8 f2 V1 r$ T: n3 A/ O
在方法中实现你的客户身份校验,而在校验之前,通过把RDM上所有的TDataSetProvider 4 N" P; d! V. s7 d8 c' N+ G6 w$ k* q: z6 q
的Exported属性关掉即可让客户端无法看到服务器端的provider 2 k: _" {1 T% q6 R& H/ I( j0 [
因为客户端实际上是在连接服务器成功后通过服务器之IAppServer接口访问 2 S+ X2 Z7 k. C: m
所有的Provider,如IAppServer::AS_GetProviderNames可以取得 " q' _8 c) ~, M
服务器端所有exported的IProvider接口名称,而所有数据的取得、修改
/ o6 `' o( ?+ U1 N3 n4 e 都是通过相应的ProviderName来指定的,如
9 Q* e+ P7 B6 n+ H3 ]1 u, m9 Rvirtual HRESULT __safecall AS_GetRecords(const WideString: ProviderName, in
+ l" A* D3 ]( ]% {t Count, int &RecsOut, int Options, const WideString: CommandText, OleVarian ( w( S1 }" h6 N) C
t & arams, OleVariant: &OwnerData, OleVariant &GetRecords_result) = 0 ; ( x! }; L2 ]3 v+ E! f$ D
取得数据方法的第一个参数就是你需要操作的数据集名称…… u% U/ b+ h0 B( v
如果你把服务器RDM上所有的TDataSetProvider::Exported关掉,
) s1 U7 Y5 }0 \& E, ?( Y t5 P3 { 则客户端看不到任何Provider,也无法通过其ProviderName取得数据
5 y3 C2 _9 P7 r( R 例如我在服务器端的RDM类中加入
2 ?" \3 z8 w0 Z* ]9 Vclass TLoginServer : public TCRemoteDataModule ) d: O/ J Z y
{
1 _( q! V3 n2 w& W: G, x" h, F...
! o# u! J# ?3 s8 |8 yprivate: // User declarations
* E' H2 M$ F7 c/ m/ ^/ h1 ?( p9 R bool FLogin; C- g0 n' \# h0 {$ P! B8 W) l' X
void __fastcall SetLogin(bool value); : x. C* G% t) A- j1 o0 A/ l5 F' C
bool __fastcall IsLogin(OleVariant &OwnerData); " }. x! A% M% q- Y8 j' v, a
...
H' X% j, g6 z, `__published: ! d3 Z) X( D& @2 Z2 k
__property bool Login = { read = FLogin, write = SetLogin }; , O3 h+ {4 S# Z/ ?) t$ T! I
}; 2 ]7 w- W0 V( X
在RDM实现类中
5 d6 h V) A0 k! T' T6 C) ^2 K( Jclass ATL_NO_VTABLE TLoginServerImpl: 。。。
5 b5 M- l; k1 ]: a1 G{
8 L4 F7 ?5 @1 U$ x; s W$ H8 Y7 V// ILoginServer 1 s, H8 b1 |5 Q$ G
protected:
b" k( v6 A/ i1 b: W; B+ Z STDMETHOD(Login()); " b0 }$ m4 ?( B! ?0 y9 e; ?+ R
STDMETHOD(Logout()); 2 B. T2 @" ]& D4 M; s, V7 R
}; & K5 \( X6 o+ Z
然后简单实现之
5 ?& ~; r" V* t) `8 v7 P1 |__fastcall TLoginServer::TLoginServer(TComponent* Owner) : H) c$ j R/ m7 d
: TCRemoteDataModule(Owner), FLogin(false)
! R4 N7 k# C" s, E. G{ 2 Q7 H8 P, m5 K' c
}
, n( S% L6 D' h+ X//--------------------------------------------------------------------------- $ L. v& g" n3 c' K8 q
void __fastcall TLoginServer::SetLogin(bool value) ; e$ y% X8 ?5 e' j
{
1 y O( T% u3 A if(FLogin != value) 7 T1 c9 Z: l. W# v- Y4 n
{ 4 p& [9 i& |: F" J
FLogin = value; + [7 [! K5 P: Z' v/ I% {
dspAnimals->Exported = FLogin; ' \" F, S, q1 F% M
} 5 E9 t- F- i" p: A i" j+ x
}
& d: ]+ l9 [4 M//--------------------------------------------------------------------------- / }" i/ F1 {; o
STDMETHODIMP TLoginServerImpl: ogin() ; G( `3 G: o' W; z
{ * A) {" v4 |# i# @
m_DataModule->Login = true; + [' D2 f) h/ P( H
return S_OK;
: ?/ p2 r! u) q x- E} * }7 I M' M5 Q6 ?- J
//---------------------------------------------------------------------------
( k4 {- [9 M1 ISTDMETHODIMP TLoginServerImpl: ogout() - x) x$ N, U" ?" J; n8 W
{
. e6 c& @! }! @; `7 G: i: V m_DataModule->Login = false;
+ b5 g1 [3 w9 |* h( ^( a T6 A, Y return S_FALSE; + ^: u- X. t' b6 q# l
} , Q( s; o7 }# k( {: B/ I) I
//---------------------------------------------------------------------------
& t4 N2 X( ]6 v( [/ N9 V$ Wbool __fastcall TLoginServer::IsLogin(OleVariant &OwnerData)
5 z$ C0 V/ g. [* b6 a+ c5 E# t0 v{
8 Z2 P: [8 r/ P2 _5 i return FLogin;
0 n1 s; g1 K- L% a* R- b0 n! n} 6 k1 Z2 Q: T1 M+ B, E
easy 这样除非你的客户端成功调用Login方法,否则他是无法使用 % y: R; P5 {8 G9 a. K3 r
dspAnimals这个数据集Provider的,成功调用后手工打开的数据集使用完全相同
$ i$ W0 `. B" V. }* |; I
z [1 y; H2 w比如客户端可以用如下代码
5 U1 c# `5 b4 u IDispatch *dispAppServer = (IDispatch*)(DM->Connection->AppServer); 4 y+ {) ]" e) k8 V
ILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer; 3 Q% s+ @, r1 R
dispLoginServer.Login();
4 M2 }0 X4 c% x% h DM->cdsAnimals->Open();
2 i- b: q1 a- ]4 {3 b: G; T实现注册,并且打开相应数据集……
/ j4 X/ _! Y8 [ + S- Z6 H8 y* a
因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对
) y! h' |( q1 _+ ~# e+ Z绝大多数程序应该足以…… |