|
, y. j f: ]) l' z4 K2 X* Y
前面hawkfly提到的在多层编程中,服务器端安全性验证的问题 % b# q% d9 q8 }9 q# D
在以socket方式实现MIDAS时尤为明显,DCOM/CORBA都有现成的
2 |! i5 X0 K& N# h安全管理功能,而socket方式在这方面比较薄弱,没有现成的解决方案 ) W3 G4 M6 t4 {& ^* _
现就我以前对MIDAS编程的理解,做一个简要的介绍, ' t Q, @9 i9 {- {
以后有时间精力再详细举例说明 3 E R* }) g1 n e) J! ?
2 G0 N# v2 N/ e4 H z3 Kwin2k中dcom的安全级别有7种,其中 + \: P( Y" E% M* i: D$ x
最低的“无”安全检查暂且不论 $ x& s9 T8 e$ Q$ b
默认的“身份验证”服务方式几句话也说不清,
1 M( _4 z: f! g/ e先放到一边,看看剩下的5种 0 O- T9 @2 X0 ]. }6 a
6 ?6 F* v% @0 Y6 n1.连接,仅对初始连接进行安全检查
6 V& s: o) p' v& t C 6 ~9 r( D. H1 C) _
因为tcp/ip是稳固的连接,因此每个连接,也就是每个RemoteDataModule " u& H! B7 U, p7 L$ ^! Y' l# i1 M
实例检测一次即可,实现方法很多,这里简要介绍一种最简单的
" M9 I; n" [1 Y! `1 ~# r" O 可以在服务器端的TypeLibrary里面为你的服务器接口增加若干个方法,如
! v; `0 u# |2 M. c1 C interface ILoginServer: IAppServer
# h7 x& S/ x% I/ Z7 |{
* @ F; [* r9 P4 a. ^" T& q [
" r: N1 T7 f6 b* i1 B( t id(0x00000001) & A# z" |4 ^! |+ r
]
! k0 U( T: `; {8 @$ b HRESULT _stdcall Login( void );
2 p/ D' e" s* P' }% T: L [
2 d7 c$ o1 \0 b( l: @) }, ~) P id(0x00000002)
! j# a5 d; q8 M: r) _ ]
d' z+ A$ f- \, B% b! A1 `! v HRESULT _stdcall Logout( void );
9 C. u. \- w x5 ]4 y+ l5 |};
+ h- X5 j0 A4 d( w8 o4 Y( c0 y 在方法中实现你的客户身份校验,而在校验之前,通过把RDM上所有的TDataSetProvider
. i0 k" |( [/ f" G4 x- _* x 的Exported属性关掉即可让客户端无法看到服务器端的provider / u) n k& v" _
因为客户端实际上是在连接服务器成功后通过服务器之IAppServer接口访问 ' f6 n& `4 R/ N7 l5 R" Q4 `
所有的Provider,如IAppServer::AS_GetProviderNames可以取得
5 x; Q7 V4 M8 M 服务器端所有exported的IProvider接口名称,而所有数据的取得、修改
i& l- [9 j# l# d+ h" e# s1 ? 都是通过相应的ProviderName来指定的,如 2 @) p* G$ O, Y7 W' y* F w7 z, f
virtual HRESULT __safecall AS_GetRecords(const WideString: ProviderName, in
- v- [' p& M' F( R2 kt Count, int &RecsOut, int Options, const WideString: CommandText, OleVarian
$ o0 H0 a9 u& G- t& t, @, |t & arams, OleVariant: &OwnerData, OleVariant &GetRecords_result) = 0 ; & h5 U. U9 B3 I! H, F2 `
取得数据方法的第一个参数就是你需要操作的数据集名称……
2 p6 g8 _. D } 如果你把服务器RDM上所有的TDataSetProvider::Exported关掉, : ?- A+ f# m+ v' @; \4 d( s
则客户端看不到任何Provider,也无法通过其ProviderName取得数据
$ ^! \' K/ p4 \3 T 例如我在服务器端的RDM类中加入
. w3 H) G6 M- i- q& Y. [# L% }class TLoginServer : public TCRemoteDataModule
' D- z6 e' N$ i" o/ V. m{
* v) N0 W5 W5 `2 L( q... ! s% @6 X+ w: `1 O7 ]3 G; M$ A
private: // User declarations / V/ }1 L3 x* O x
bool FLogin;
6 d3 H: F0 }) E4 u. F0 v void __fastcall SetLogin(bool value); * {) k( I; ]4 P3 q% [
bool __fastcall IsLogin(OleVariant &OwnerData);
$ X- T1 P* @' k+ @...
& l" Y) u$ H6 B! a& N4 ~9 q7 S6 W$ I__published: 0 _' \: Y* C8 r+ q
__property bool Login = { read = FLogin, write = SetLogin };
1 d ]% w7 ]0 K2 u' o+ J};
% W* k& G6 R! y- ~- h在RDM实现类中 ! _# z% x; A' Q4 Y0 N
class ATL_NO_VTABLE TLoginServerImpl: 。。。
1 h# n8 N, n+ T0 z1 Z2 r! v{
2 k' ?- V& ~% g1 `// ILoginServer
( c* S2 j% }2 l1 `' f* R3 m5 @$ pprotected: 3 d: |2 C4 K1 O+ T% q0 N& ]" A9 ]
STDMETHOD(Login()); 5 T1 k7 z7 n% e( Z; j1 v1 D
STDMETHOD(Logout());
. g# X W" N7 |& ]};
2 G* ]+ e4 @% R1 H. n4 m3 ?然后简单实现之
) E- o" f% h8 q; _$ m+ V__fastcall TLoginServer::TLoginServer(TComponent* Owner)
% O: @* R) Y; ]+ z4 R* T) ] : TCRemoteDataModule(Owner), FLogin(false) 2 A& H) ?2 s0 a
{
- @: M2 ~, i, s( G' s% K} N7 n: t: A& U- ~* ^. T( Z
//---------------------------------------------------------------------------
' s2 O$ x [$ B& R6 Pvoid __fastcall TLoginServer::SetLogin(bool value)
* M; w/ O i. C3 U{
- R1 o! H( h( a+ t# m! C C if(FLogin != value)
& X! H* J) R! T {
) T% B, |' x( t/ F+ R, T FLogin = value;
/ i; g) s7 x+ s0 g& b# t dspAnimals->Exported = FLogin;
4 X5 F! Q5 V/ n1 F2 B# i( h } ! z, y2 ]$ s9 }- Q3 U7 t1 g% \4 \
} ' e! s7 P- u. p" _& K
//---------------------------------------------------------------------------
, S6 f1 j/ `, f9 z+ A) Q1 W% sSTDMETHODIMP TLoginServerImpl: ogin() 3 c" t' _8 p6 w, K) s
{
* Q( a( V* p6 S m_DataModule->Login = true;
0 J8 u+ o+ ~' @) r& S! o+ g return S_OK; ' `6 M; G+ M- E3 ~
} - K, P7 h! A7 J8 ]/ A9 _
//--------------------------------------------------------------------------- / Q$ s+ T! w3 }/ y9 Q7 I0 K
STDMETHODIMP TLoginServerImpl: ogout() : ?+ V3 b: C: D4 H6 {1 F o- D
{
$ Q* z, D( ?0 e m_DataModule->Login = false;
( M5 X$ y; P% h p$ j3 f3 j/ G# H, B return S_FALSE;
j4 U' m- ? X: H}
. @2 V# k3 D: e- F//---------------------------------------------------------------------------
2 A5 k: b" g6 J: H; Bbool __fastcall TLoginServer::IsLogin(OleVariant &OwnerData)
# K2 N9 N8 u6 s d{ ; q, M" w) G1 s6 X8 ~
return FLogin;
( j6 `- M0 w: E A0 h1 S/ W} : ]$ r' Q: ~) K) K8 v: p2 ~: T
easy 这样除非你的客户端成功调用Login方法,否则他是无法使用 1 ^2 y1 A& n4 ^9 `
dspAnimals这个数据集Provider的,成功调用后手工打开的数据集使用完全相同
1 M( [( ?* V& s- r- K' k& E" J
1 b9 F1 c6 R; l5 _% W比如客户端可以用如下代码
3 K" ~( \# J9 L/ N( _ IDispatch *dispAppServer = (IDispatch*)(DM->Connection->AppServer); ) s+ `4 H* {- ]1 d
ILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer;
# n/ X0 \/ c9 x. X5 R ^ dispLoginServer.Login(); ' D! }% W/ e7 y, i
DM->cdsAnimals->Open();
3 }! f& r2 F S* Y2 U. Q实现注册,并且打开相应数据集……
. Y, o. \( B7 x# d3 s
/ S+ N% z+ B6 [) o" R% k因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对
/ H% p& K/ ]# D% t) @绝大多数程序应该足以…… |