|
) b. a/ }7 s/ ] V; b) X
前面hawkfly提到的在多层编程中,服务器端安全性验证的问题
) a+ h% T, m; I' L; p0 s, H7 w e在以socket方式实现MIDAS时尤为明显,DCOM/CORBA都有现成的 % [) ^7 ~& }& [& [
安全管理功能,而socket方式在这方面比较薄弱,没有现成的解决方案
- [2 ?0 B' D8 t/ \现就我以前对MIDAS编程的理解,做一个简要的介绍,
- l7 l6 I% `0 Y. x以后有时间精力再详细举例说明
/ ^( G; J* g0 q. S. ] " H, |! Z) |/ Q+ c7 J8 X
win2k中dcom的安全级别有7种,其中 6 L* F) j5 a5 H
最低的“无”安全检查暂且不论
1 |! s' d d: A" w默认的“身份验证”服务方式几句话也说不清,
* F! q+ Y; X% ]$ J% E先放到一边,看看剩下的5种
7 d4 n% {/ d# {8 h. F; x
3 s+ _, {5 N: g! F. K9 H+ c; p2 l1.连接,仅对初始连接进行安全检查
! q. P. U# m" F
6 C9 @! M( h8 _1 ^$ ~% { 因为tcp/ip是稳固的连接,因此每个连接,也就是每个RemoteDataModule
. H, t! X$ W1 R& @ 实例检测一次即可,实现方法很多,这里简要介绍一种最简单的 3 c7 r$ S' i$ W* J5 t" g" L. t
可以在服务器端的TypeLibrary里面为你的服务器接口增加若干个方法,如 7 Q# g& H1 ? B
interface ILoginServer: IAppServer % Y7 g1 I+ i1 l! z* l4 N
{
* S3 P' s* q" n. F4 y+ \ @ [
' ^* y# \- v; Q2 i5 w' c id(0x00000001) 2 w; e! T0 E. d7 ], F+ J
]
6 b G( z2 S) W. h* n) o5 E HRESULT _stdcall Login( void );
8 \' [7 L& `5 L {5 i w2 |9 x; c [
. f4 Z4 A2 T8 x H9 f8 z2 J7 A id(0x00000002) 0 M- _' G7 w7 N5 J
]
7 g0 i5 s+ I9 N+ q4 z HRESULT _stdcall Logout( void ); , K' E9 Y" x7 N
};
9 h" L% U v9 b7 w. Y! W 在方法中实现你的客户身份校验,而在校验之前,通过把RDM上所有的TDataSetProvider 8 i9 R( b* N. Y# g) J% r- G
的Exported属性关掉即可让客户端无法看到服务器端的provider \" E: n& B8 b" u6 g! j
因为客户端实际上是在连接服务器成功后通过服务器之IAppServer接口访问 , n" b0 p4 N+ m4 h* Y- }: w
所有的Provider,如IAppServer::AS_GetProviderNames可以取得
) N. ~. Z6 b/ U 服务器端所有exported的IProvider接口名称,而所有数据的取得、修改 , p5 g5 A7 _- V8 z2 d% \2 A
都是通过相应的ProviderName来指定的,如 : [' A5 r6 E7 [) A- V
virtual HRESULT __safecall AS_GetRecords(const WideString: ProviderName, in 5 K- X2 E) ^1 P8 T+ {1 n- l
t Count, int &RecsOut, int Options, const WideString: CommandText, OleVarian 9 }: s1 u* I) u5 G& a; g' f
t & arams, OleVariant: &OwnerData, OleVariant &GetRecords_result) = 0 ;
& w" N9 W& [0 ] 取得数据方法的第一个参数就是你需要操作的数据集名称……
5 K6 s2 V1 C9 n. K% [ 如果你把服务器RDM上所有的TDataSetProvider::Exported关掉, ) ], z& x6 T v% x
则客户端看不到任何Provider,也无法通过其ProviderName取得数据
1 D1 ]3 g8 ?# |: w8 k9 Q: f& h 例如我在服务器端的RDM类中加入 " P6 {( K% @1 T. T( {7 p9 o% T
class TLoginServer : public TCRemoteDataModule
; [: Y. A% Z" u: m& r# ^4 o{ - c' @' v9 H! J+ {" @" s
...
0 `: d9 b' G4 v6 v5 @$ cprivate: // User declarations 3 B: x1 @+ U+ S/ ~6 n
bool FLogin; # p9 |& K) ^+ k
void __fastcall SetLogin(bool value); 3 u9 f& v2 }; B0 I4 j U
bool __fastcall IsLogin(OleVariant &OwnerData);
& \" w& |& h( }. q) P% N... * Q/ p! y- I5 [9 m1 a, q9 |2 }$ \
__published:
4 O' R! |. W6 j9 h __property bool Login = { read = FLogin, write = SetLogin }; 0 y3 u* s. r" {( [; k5 K0 A T
};
- P/ B6 b& r' i4 e在RDM实现类中
) y, @$ h8 C- e/ o; ?3 O9 {2 S4 dclass ATL_NO_VTABLE TLoginServerImpl: 。。。 2 l9 e' v& h$ a
{ $ p$ U3 q, }1 J/ L' D
// ILoginServer - n+ V- N! h% i! e$ \2 e* X; _% M4 }
protected: . n& i+ G% e& G% y, @- a) e
STDMETHOD(Login());
. H$ E9 e% q" W STDMETHOD(Logout());
4 u) ~2 ]4 {) g}; 6 w2 w4 b+ r6 N
然后简单实现之
% t2 h% d: I6 C( k__fastcall TLoginServer::TLoginServer(TComponent* Owner) & u, t2 Q: V! F/ ^$ N9 L, p
: TCRemoteDataModule(Owner), FLogin(false) , z; I7 E4 B& |; H9 |
{ & I3 t4 B' F* \6 g
} ; ?/ ?: h9 w3 h) r3 ?1 Z8 \0 {& S5 X
//--------------------------------------------------------------------------- 6 b5 Z1 L- M, p! [
void __fastcall TLoginServer::SetLogin(bool value)
3 r+ K ?" B! }( F4 {{
- v% M5 D2 D' o# W! Q: [8 ^# |8 g if(FLogin != value) $ J& K7 n) }1 C
{ ' u( e( G) r6 X) ]; b# R
FLogin = value;
7 E$ N% _0 v1 e- ~: p dspAnimals->Exported = FLogin; 2 h. w6 ]8 ?9 l) K; H
} : f) }9 B4 ]( H5 v; a8 Y
} + i. n2 ^3 p- ^8 h1 f
//--------------------------------------------------------------------------- 4 n/ h, L! A( O, p+ R
STDMETHODIMP TLoginServerImpl: ogin()
0 o0 r, }0 C+ U4 d" u J{ + r( P: k& |) d4 K
m_DataModule->Login = true;
, A# C* O5 @1 C return S_OK;
) a9 S1 X d1 S}
7 v3 I5 w+ S# P6 i6 U//--------------------------------------------------------------------------- / N! Z) {7 ^$ p' c8 a% f
STDMETHODIMP TLoginServerImpl: ogout()
4 y% p' ^$ P* v* p! T{
, m& h! L- r4 a, n m_DataModule->Login = false; 8 N1 U3 g/ q$ _& J
return S_FALSE;
, k( g9 j0 j! R}
4 C% w7 N& J* D" {* U# ^//--------------------------------------------------------------------------- % M: u# {+ z; S7 t4 Q" q
bool __fastcall TLoginServer::IsLogin(OleVariant &OwnerData)
0 e$ p, K- A8 J* w9 \- n e9 L{ ; ?* J/ i3 M8 Z9 b; }$ W7 `9 j# z) K* k9 p
return FLogin; % P. y0 Y% q+ W1 k6 G& I" R# i+ c
} 1 R" f5 |5 G! B$ o% g
easy 这样除非你的客户端成功调用Login方法,否则他是无法使用
% `8 J z2 w7 b) ddspAnimals这个数据集Provider的,成功调用后手工打开的数据集使用完全相同 . e. p$ k" a) {# q- t4 f; R( @ @
2 l4 E$ ~$ ?5 i: E7 r3 \比如客户端可以用如下代码 5 q% }/ V. j1 r6 z. ?( s) }; W1 l5 r
IDispatch *dispAppServer = (IDispatch*)(DM->Connection->AppServer); ( g' b4 ]6 ]5 U) v6 C5 _* e! ?
ILoginServerDisp dispLoginServer = (ILoginServer *)dispAppServer; ; F# N' k. i' C0 c
dispLoginServer.Login(); 5 Z4 z0 Q ?2 j1 o1 f6 C% M: I; z
DM->cdsAnimals->Open();
, {7 t- v7 W$ f u& f7 X2 I. z实现注册,并且打开相应数据集…… ; C" p9 p- _. s) ]4 e
1 L+ S# E5 }" O$ q4 E/ N7 G! A. V因为大多数的三层程序对安全性要求并不高,因此这样的安全检测对
2 H1 A4 I: U5 y4 K+ O/ F$ m0 O6 W$ [, ]绝大多数程序应该足以…… |