|
' q/ O5 F$ v( n' ]前面hawkfly提到的在多层编程中,服务器端安全性验证的问题
% c( z& E- Q- w8 z5 o. r在以socket方式实现MIDAS时尤为明显,DCOM/CORBA都有现成的 2 k2 W4 b. M+ q5 u8 S* e) T
安全管理功能,而socket方式在这方面比较薄弱,没有现成的解决方案
1 G0 v d# E0 f- D现就我以前对MIDAS编程的理解,做一个简要的介绍, + [) ^& Q6 j3 _. i1 b; t& y5 g% u. ?
以后有时间精力再详细举例说明 2 `5 ^. F1 V. g! n* _* p! I# x
/ `1 ]9 Y6 l% @4 Q1 M2 m, Iwin2k中dcom的安全级别有7种,其中
1 A0 z% `5 a# m! j最低的“无”安全检查暂且不论 $ [7 u4 X0 a9 v0 V6 A+ Q
默认的“身份验证”服务方式几句话也说不清,
6 p$ V9 o) }) H4 l9 p5 c7 S* J! {先放到一边,看看剩下的5种 : F ]) T4 i3 k/ ?: \) V6 f
# i z8 L; x5 S1 O; M$ Q
1.连接,仅对初始连接进行安全检查
! o: T4 e- f( f
/ r" @: Z" ~ R, N, D2 X* C/ L 因为tcp/ip是稳固的连接,因此每个连接,也就是每个RemoteDataModule 9 D( f) n; E1 k- c
实例检测一次即可,实现方法很多,这里简要介绍一种最简单的
+ f) s/ v5 ^& T6 G' ~9 C; [ 可以在服务器端的TypeLibrary里面为你的服务器接口增加若干个方法,如 : j1 m1 l0 c4 u1 F9 A( c! I
interface ILoginServer: IAppServer
- C/ s9 q- t: q5 T! V{
1 H& v/ h3 Z2 { [ a5 I E+ K; N) [
id(0x00000001) 4 k" O+ B) |/ k) W. M( U
] 9 q0 m( h' G! Y3 A6 f
HRESULT _stdcall Login( void ); 8 _- D$ q1 a0 b* D
[ + T1 X- g" F8 W9 c. [
id(0x00000002) . l/ N& R) }. N/ i7 k3 P
] + I" N. Q* @/ i* D, C
HRESULT _stdcall Logout( void );
, T: r. F0 `5 y9 O}; 2 a* Q1 W" Q& O5 | P* ]
在方法中实现你的客户身份校验,而在校验之前,通过把RDM上所有的TDataSetProvider * F) H9 y5 I9 n
的Exported属性关掉即可让客户端无法看到服务器端的provider
3 Y" u2 b+ j0 Q. y5 r ] 因为客户端实际上是在连接服务器成功后通过服务器之IAppServer接口访问 ! Y* d, }4 |% p% B( M4 n7 @" P
所有的Provider,如IAppServer::AS_GetProviderNames可以取得 / G; f' k* ^! p/ C& S9 M% b) `
服务器端所有exported的IProvider接口名称,而所有数据的取得、修改
7 c+ m5 @$ V" T l4 m9 U 都是通过相应的ProviderName来指定的,如
9 C5 U/ t; K f* e" b% n1 uvirtual HRESULT __safecall AS_GetRecords(const WideString: ProviderName, in
; E8 ]! f& l' Z0 ]! J e* Zt Count, int &RecsOut, int Options, const WideString: CommandText, OleVarian ' b, g* e. Y# B7 l
t & arams, OleVariant: &OwnerData, OleVariant &GetRecords_result) = 0 ;
) q$ r% [3 J3 T" S: h 取得数据方法的第一个参数就是你需要操作的数据集名称……
7 _/ C* p4 }/ U% L! A 如果你把服务器RDM上所有的TDataSetProvider::Exported关掉,
& U. p8 k w5 D) |) m 则客户端看不到任何Provider,也无法通过其ProviderName取得数据 1 x: i7 u W( e% R; Z) @
例如我在服务器端的RDM类中加入 # O* W5 Z D- D& T
class TLoginServer : public TCRemoteDataModule
. H. ^: L! B+ f7 r, @% e7 y{ ) h8 p$ [3 N) m1 C' S
... % v( z8 N7 j# C: \9 ^: d
private: // User declarations
7 ]/ H. T. o8 Z3 @/ q6 X bool FLogin; " ?/ [9 G1 e( e$ u6 }; N2 y" h
void __fastcall SetLogin(bool value);
* ^( d, R8 U Q bool __fastcall IsLogin(OleVariant &OwnerData); ( B3 }" @8 p! p. \
... ! P( z: s/ `6 W8 ^2 n5 N/ a9 @
__published:
% m8 s0 i3 D9 R8 Y1 Y __property bool Login = { read = FLogin, write = SetLogin };
2 P2 l8 e% \! E) |8 i};
. G- g2 i- U( ]" a$ [6 h; a; U9 c在RDM实现类中
% S7 d2 d0 @7 T Q; Dclass ATL_NO_VTABLE TLoginServerImpl: 。。。 + C" U: h2 x+ {
{
) w1 v% P' d* |% l c; b; s// ILoginServer
8 h. b) p H- O3 D7 H0 wprotected: $ N ]0 p R/ l
STDMETHOD(Login());
: d v# a. ]4 ?4 H1 w ^ STDMETHOD(Logout());
* s8 N$ F0 {" Z; ^& u};
1 G! x7 O. V) a然后简单实现之 0 n7 F* r6 c* t1 x+ B$ S
__fastcall TLoginServer::TLoginServer(TComponent* Owner) ; z8 h1 R9 Q' z8 C
: TCRemoteDataModule(Owner), FLogin(false) 0 @5 J. B! q3 [# T- K& r8 P
{
2 I N# l1 y$ h0 ~6 X}
5 ?& }+ E: ~7 ~; k/ @//--------------------------------------------------------------------------- " P0 t; n$ a( v" x) M
void __fastcall TLoginServer::SetLogin(bool value)
, N0 U, K4 _3 { m6 X7 K1 S# ]/ E{
3 N4 ]7 ?; [* I/ w( x, O" e if(FLogin != value) / T% S$ P# B H* J* E
{ # ]' A. ~; |% `2 w u
FLogin = value;
1 g) Q0 r& P3 X; S+ c7 ~* r dspAnimals->Exported = FLogin;
7 r, R0 J2 {2 U) c: u } : l+ s# n3 E9 f; J
}
+ {( O8 P# T" C/ H0 y0 U//--------------------------------------------------------------------------- ) w+ h: ~& e1 ~/ [) `
STDMETHODIMP TLoginServerImpl: ogin()
/ X/ t2 k" o; a{
9 g; ~8 D3 `: S2 X/ C, A# E m_DataModule->Login = true; : E; B1 i/ M* f3 ^3 W' S
return S_OK;
3 u9 x* @! y* A. p) O3 X. o. q} ; @0 \' }4 S8 J
//---------------------------------------------------------------------------
/ K1 U2 B1 w+ ^& KSTDMETHODIMP TLoginServerImpl: ogout()
' ^6 G5 t% q" H' E# t6 G{
# f8 H% P- k0 q+ ] m_DataModule->Login = false; 9 z( K8 d- v; q2 m
return S_FALSE; 1 Q( {- X* A4 P# j+ E# G6 h S
} " x _5 i1 Q |! b2 G; y+ R
//--------------------------------------------------------------------------- 7 E+ I: g: \% X
bool __fastcall TLoginServer::IsLogin(OleVariant &OwnerData) . i! q) w% ?4 ?7 V& t
{
3 Y9 \1 \6 K/ n: b) I return FLogin;
5 \2 \* p& p) M: K. U* S}
# B" g- I% Y) f% [! P. seasy 这样除非你的客户端成功调用Login方法,否则他是无法使用 8 g. J( f7 X5 K; s8 i+ Y" \' b
dspAnimals这个数据集Provider的,成功调用后手工打开的数据集使用完全相同 % \: e+ X* i T, I; A& `5 a- I
& A& k) {% y& S) {4 p" p% `比如客户端可以用如下代码 l8 M5 U" u/ B* V
IDispatch *dispAppServer = (IDispatch*)(DM->Connection->AppServer);
. g3 W& t) z' v4 N! v; b/ j ILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer;
3 ^$ `$ N; Z/ [/ [ dispLoginServer.Login(); " f; m2 T) I- @! d
DM->cdsAnimals->Open(); , J2 d3 O: f8 ?: p' @. W/ V
实现注册,并且打开相应数据集……
% h( l/ V7 M% e/ A' P! D: m
+ S8 f- i- N' e9 ~因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对
; y+ c% z9 }8 s( s" k9 R7 k绝大多数程序应该足以…… |