|
& H: {3 a- @( A- G/ Q5 e
前面hawkfly提到的在多层编程中,服务器端安全性验证的问题
% Q* j* m4 p7 s在以socket方式实现MIDAS时尤为明显,DCOM/CORBA都有现成的 / @6 Z. H. i9 g
安全管理功能,而socket方式在这方面比较薄弱,没有现成的解决方案
$ C1 \7 t3 v3 y现就我以前对MIDAS编程的理解,做一个简要的介绍, ( N; R0 S F7 H8 C2 ]
以后有时间精力再详细举例说明
: B( v: i; U* t, X 8 u! y' w- l6 b$ x& H9 A
win2k中dcom的安全级别有7种,其中
. ]- Y9 B6 u6 X% C5 {' _- B; W最低的“无”安全检查暂且不论
) Z q% A' n$ J; x* Q默认的“身份验证”服务方式几句话也说不清, / r. |" _, Q. H3 i/ Y8 s
先放到一边,看看剩下的5种
" @, `7 f3 K) p$ C8 m
! l! O0 E& c7 ^' t/ \1 {! J- q1.连接,仅对初始连接进行安全检查
# _" k- A/ F3 C: {, Z: C
! u5 @$ v1 ]9 G2 o 因为tcp/ip是稳固的连接,因此每个连接,也就是每个RemoteDataModule
1 n v+ S" [8 b1 R8 B- b$ I 实例检测一次即可,实现方法很多,这里简要介绍一种最简单的 $ X* T/ u) ]" b6 z5 F: v* q
可以在服务器端的TypeLibrary里面为你的服务器接口增加若干个方法,如
2 u) N5 b+ W/ L5 G) R( O interface ILoginServer: IAppServer % ?( ]8 P2 R H- w. T( I* f
{ , m3 `$ @* K2 U9 x
[ 3 o" i; U' K! c( i3 c! K5 Q9 w
id(0x00000001) n- G3 a3 Z' }, l' k6 m
]
$ l% L7 w& h+ ~3 H HRESULT _stdcall Login( void );
: g0 d7 q% ^" M; U4 ^! j [
1 ~7 E1 g; h* B id(0x00000002) 9 ~* t) X- B4 D, g2 z$ x
]
2 q, z2 P8 L" R HRESULT _stdcall Logout( void );
8 K3 m8 e6 c5 d, [: l};
. Z1 B `7 _: b6 k8 ^0 X7 I/ R. }; D Q 在方法中实现你的客户身份校验,而在校验之前,通过把RDM上所有的TDataSetProvider
: v* w8 g$ Y# T5 X# @; ] 的Exported属性关掉即可让客户端无法看到服务器端的provider / e8 O- Q! i$ D5 J
因为客户端实际上是在连接服务器成功后通过服务器之IAppServer接口访问 / x1 F3 I/ P- G6 J) v0 {
所有的Provider,如IAppServer::AS_GetProviderNames可以取得
; ]9 W' ?) [. w( R 服务器端所有exported的IProvider接口名称,而所有数据的取得、修改 0 ~, z' M7 Z( E J$ Q) v
都是通过相应的ProviderName来指定的,如
# ?6 M' C" |* e' n) J' `virtual HRESULT __safecall AS_GetRecords(const WideString: ProviderName, in
+ j% K2 o4 ]- k( ?. Qt Count, int &RecsOut, int Options, const WideString: CommandText, OleVarian ! H+ J |' j: V: \( d
t & arams, OleVariant: &OwnerData, OleVariant &GetRecords_result) = 0 ;
! F( J' p% F' Y 取得数据方法的第一个参数就是你需要操作的数据集名称……
7 Y$ h4 f" W- ~ 如果你把服务器RDM上所有的TDataSetProvider::Exported关掉,
: q2 m- {* G4 l9 @2 G1 G 则客户端看不到任何Provider,也无法通过其ProviderName取得数据 " B! W6 ?+ p! ?( a3 O, ~. G
例如我在服务器端的RDM类中加入
) Z! _+ M' I5 _. M: T9 w1 Mclass TLoginServer : public TCRemoteDataModule
( `9 i6 w+ I% U- S; [# W: E' V{ + Z" X8 N" C. `, @: J3 N3 x
... H- X' X0 [+ e/ f' K
private: // User declarations 9 ~" H, n. ]2 H% j
bool FLogin; + z! Q8 G6 A7 K" P9 ~( a- x
void __fastcall SetLogin(bool value); ( Q4 N; Y3 @: a; x5 {; b0 H/ g
bool __fastcall IsLogin(OleVariant &OwnerData);
/ f* W8 ^! z2 F) U...
# `: e/ Y J, I, v8 m__published:
0 N2 D/ I9 S* L% J __property bool Login = { read = FLogin, write = SetLogin }; 7 e) c9 K+ Q" h0 a
};
6 g7 y! s" I7 [, v在RDM实现类中 7 Y6 m" ?7 a$ c5 i" V6 ]
class ATL_NO_VTABLE TLoginServerImpl: 。。。
# L" n/ l, K- v9 G{ 4 @: ~; H% T, R4 O0 ], f
// ILoginServer 3 m2 k+ k& ]+ v* c$ N* \
protected: $ O. B) a. F$ C1 j2 I5 Y3 M
STDMETHOD(Login());
/ B- C! E4 ~3 l* D4 A STDMETHOD(Logout());
' h6 W4 ?: e" I2 n}; 1 l2 E% t6 o# w3 y0 F$ b8 f, k" b
然后简单实现之 * v. t3 e4 v5 `" ?
__fastcall TLoginServer::TLoginServer(TComponent* Owner) 5 G9 z0 t6 W3 H7 U
: TCRemoteDataModule(Owner), FLogin(false)
. \. c3 C( C+ x5 b# R{
0 ?/ _* Q, U& G, b5 V} / d0 X: \' S4 r. M$ r/ ?8 h
//---------------------------------------------------------------------------
S* B6 |6 d' u$ u) C9 qvoid __fastcall TLoginServer::SetLogin(bool value) / }& B2 g0 k# x1 K m# ~" S+ y7 F( {
{
, ` X: G* L9 a% B8 B if(FLogin != value)
) S- N3 s ~+ A7 C, t5 N { . g# F& y3 Q, `/ P( ]/ a/ v* ^
FLogin = value;
8 U1 G8 _# c' u. A dspAnimals->Exported = FLogin;
' ?9 K5 ]8 ~3 o0 L }
7 A. }6 Q9 {( s1 H* b {}
7 ^2 W c a5 X' p0 b//---------------------------------------------------------------------------
! }0 z: c* \ D+ ZSTDMETHODIMP TLoginServerImpl: ogin() 4 p& `) T( X5 i- V
{
9 ?% V; o2 i H$ D" ]! g: i3 l m_DataModule->Login = true;
( Y! }! S k1 t return S_OK; + J' |$ X& a: b6 c% \! B$ w
} ( R- ~" d' I' Y1 O/ V5 |
//--------------------------------------------------------------------------- 0 _/ t) p3 f- v5 a9 y
STDMETHODIMP TLoginServerImpl: ogout() : }* L) q; H$ t" y! G7 [8 D
{
5 Q4 p, z( c# j% r7 ]$ D: Z: M6 s m_DataModule->Login = false; ( j: J& b* D5 ^0 o
return S_FALSE;
4 b( L* w/ I) ~2 ]4 M! V6 E- Z+ |}
0 ], ^, j4 Y* V5 O5 w- B//---------------------------------------------------------------------------
5 _% I; a" {0 H2 r0 c; O3 \bool __fastcall TLoginServer::IsLogin(OleVariant &OwnerData)
$ ]9 q9 Z5 ]0 y3 c# H* z( ~{
# A, V8 }1 }, g. V( N return FLogin;
5 c y' D& u$ Z7 F5 p+ ^! @$ K}
* h3 J0 U- f, q* S% ceasy 这样除非你的客户端成功调用Login方法,否则他是无法使用 # b- g) m$ S8 @' t7 V
dspAnimals这个数据集Provider的,成功调用后手工打开的数据集使用完全相同
$ p" G( E. y; L! W
# J2 x; S) I# H. _" R; T9 j比如客户端可以用如下代码 1 o% I1 a$ P' I ]0 P* n1 J
IDispatch *dispAppServer = (IDispatch*)(DM->Connection->AppServer); 1 c$ W* u- C0 S6 Z1 R4 g9 |) X
ILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer;
" K6 k! q$ y* J; O& Z' F dispLoginServer.Login();
. p9 w9 J$ F! |9 i DM->cdsAnimals->Open(); ( @7 z# e# M+ y& N! w
实现注册,并且打开相应数据集…… ) Y/ b; L8 \4 R5 |1 G
6 |9 y5 D' Q. w: u0 F7 r% I' w3 ~
因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对 5 v5 ~2 x) _, g) J _$ o. Z- R7 @
绝大多数程序应该足以…… |