动态Proxy与Java ACL用户访问控制机制实现
用户访问控制(Access control )机制总是围绕粗粒度和细粒度两个方面来讨论:
; q# t+ ^1 p. ?7 {" k我爱电脑技术论坛
4 q5 t- y1 K& O我爱电脑技术论坛
, _! m$ [9 N+ r) x8 c7 A* _* O我爱电脑技术社区--打造最好的电脑技术自学交流平台粗粒度控制:可以规定访问整个对象或对象群的某个层,而细粒度控制则总是在方法或属性层进行控制,比如: 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站- z! G6 o9 f% Z7 d4 }- y' W0 v
打造最好的电脑自学交流论坛5 N8 V7 L5 F/ o8 n3 i# ]* _4 O& \
0 X' N/ e- U) w# I1 o8 K
允许一个文件为只读是属于粗粒度控制,而允许对这个文件某行有写操作则属于细粒度控制。
' U* h$ Z+ ~! c9 F7 I$ D0 K$ T我爱电脑技术论坛
% D/ k. U6 H+ S1 C' W+ L; O我爱电脑技术社区--打造最好的电脑技术自学交流平台
5 _. x% ~4 |) k$ _" b我爱电脑技术论坛一个好的用户控制机制当然既允许粗粒度也允许细粒度控制,在Jive中我们看到是使用Proxy来达到这个目的,但是我们也发现,由于需要对每个类都要进行细粒度控制,所以必然对每个类都要做一个Proxy类,这样带来了很多Proxy类,如ForumProxy ForumThreadProxy ForumFactoryProxy等,无形增加了系统复杂性。 我爱电脑技术社区--打造最好的电脑技术自学交流平台) y# \; [& I% P) Y2 \* ?; {# }7 ?
3 a0 _$ F9 y3 n/ G6 nwww.520diannao.com
# x! k$ D4 Y* O6 @6 q. W我爱电脑技术社区--打造最好的电脑技术自学交流平台使用动态Proxy可以很好的解决这个问题。再结合java.security.acl的ACL机制,我们就可以灵活地实现粗粒度和细粒度的双重控制。 我爱电脑技术社区--打造最好的电脑技术自学交流平台# J: r+ b/ P5 O6 ]. t- y
; C3 Y, l: |) M. p4 T& }" ~5 }/ `+ N
: T |' r6 R0 ]9 h8 F6 D- f+ V; N电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站当一个用户login后,我们就要在内存中为其建立相应的授权访问机制,使用java.security.acl可以很方便的建立这样一个安全系统。
2 H' G8 L! j; ^. P! ~
. O; L9 V7 G1 ]% }
! V% t; a$ T/ g2 l$ m- g+ Z2 m我爱电脑技术论坛首先任何一个对象都应该有个基本属性:拥有者 或拥有者所属组(Windows中每个目录安全描述符都由4部分构成:对象的创建者、对象所属的组、自由存取控制和系统存取控制)。
6 t5 M/ Z, D& X9 f- X8 z/ x- _7 l我爱电脑技术论坛' b; }! ~: b6 Z3 ~6 p; f
1. Java acl开始第一步是建立一个主体 Principal,其中SecurityOwner是主体的拥有者: private static final Principal _securityOwner = new PrincipalImpl("SecurityOwner"); 我爱电脑技术论坛+ Y& K5 G1 e* D# v6 X) S
5 v% ]4 R# k d: A. A我爱电脑技术论坛2. 当用户login进来时,他带有两个基本数据:访问密码和他要访问的对象ApplicationName。首先验证用户名和密码,然后从数据库中取出其权限数据,建立Permission,这里使用Feature继承了Permission,在Feature中定义了有关权限的细节数据(如读 写 删)。
: S% X- }% k$ {' F: I% a7 Vwww.520diannao.com我爱电脑技术论坛, ]8 q+ S6 B& T. q$ S
// 取出用户和被访问对象之间的权限关系,这种权限关系可能不只一个,也就是说,用户
7 b# r0 \' e8 M6 ^! \电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
$ e5 q& U" ~( R2 n( S: h打造最好的电脑自学交流论坛//可能对被访问对象拥有读 写 删等多个权限,将其打包在Hasbtable中。 打造最好的电脑自学交流论坛4 ~ Q/ j/ f1 o' b% {- ^6 D
6 O: r8 g* T$ Z* }; W6 F# Y9 X; w2 i3 S我爱电脑技术社区--打造最好的电脑技术自学交流平台Hashtable features = loadFeaturesForUser(sApplicationName, sUserID);
' h8 Q9 N& ]1 m/ T5 z我爱电脑技术社区--打造最好的电脑技术自学交流平台
6 A9 ]( u$ V: W1 C( O+ F9 K: N5 a电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站3. 创建一个用户对象
, @: P( t' S& W我爱电脑技术论坛
: E& X2 P& O9 }; ?打造最好的电脑自学交流论坛User user = new UserImpl(sUserID, new Hashtable() ); 我爱电脑技术论坛( Y% w0 c# v4 v% j; u& u5 Z
2 d, l+ r* ^% v6 b8 M+ x打造最好的电脑自学交流论坛4. 为这个用户创建一个活动的acl entry
1 o3 M( a& M/ S: }2 T我爱电脑技术论坛www.520diannao.com. }6 J* M# k g% W) J
addAclEntry( user, features); 我爱电脑技术论坛2 I$ k& ~. s! j9 {8 r8 ^& R
我爱电脑技术社区--打造最好的电脑技术自学交流平台$ }, L; _7 p5 ]2 K" C! t' W
其中最关键的是第四步addAclEntry,我们看看其如何实现的: 我爱电脑技术社区--打造最好的电脑技术自学交流平台# j |9 @; M+ C" l; S# `
我爱电脑技术论坛# ^+ S6 N! \$ \6 K4 g' h
// 为这个用户创建一个新的Acl entry
5 G) ~0 N" c9 d+ F' [& e打造最好的电脑自学交流论坛打造最好的电脑自学交流论坛7 y; r8 m2 [* N$ \1 k' t
AclEntry newAclEntry = new AclEntryImpl( user); 我爱电脑技术论坛' J! H- F! A( C8 b
打造最好的电脑自学交流论坛$ y! h; x4 C* }$ S- X! g/ Z
//遍历Hashtable features,将其中多种权限加入: 我爱电脑技术论坛) ~9 H: Z" J( Q1 ^
我爱电脑技术论坛# D6 c+ D; |' F% `4 m+ Y
.... 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站* c, b" \) e5 W
我爱电脑技术论坛' n: n# K7 M9 C4 \* E9 ?& G) Y
feature = (Feature) hFeatures.get(keyName);
8 j. f8 X. o+ q% U3 m# {5 ^7 \$ u% kwww.520diannao.com
# ]! G% Z: X: ]( r3 a8 N1 g% O我爱电脑技术社区--打造最好的电脑技术自学交流平台newAclEntry.addPermission( feature ); 我爱电脑技术论坛0 _/ H" V% d% Y6 K c0 W# P
+ t* t, O& h! I; c我爱电脑技术社区--打造最好的电脑技术自学交流平台.... 9 q/ S* V2 ]$ E" h; y1 _
' H( B; r" a4 {/ V J# Q) Z我爱电脑技术论坛最后也要加入主体拥有者SecurityOwner
$ r' ^: L6 `4 j! G% x我爱电脑技术社区--打造最好的电脑技术自学交流平台
, G, k" I' ^* f. b4 G6 N8 U打造最好的电脑自学交流论坛这样一个安全体系就已经建立完成。 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站9 X: E1 s3 h2 p+ |+ o
2 ?- q. s0 w& T4 C( L: V) ]
5 `4 v' `0 C. u( Z: z* Y我爱电脑技术论坛当你在系统中要检验某个用户使用拥有某个权限,如读的权利时,只要acl.checkPermission(user, feature )就可以,acl是ACL的一个实例,这样权限检查就交给java.security.acl.ACL 去处理了。 我爱电脑技术社区--打造最好的电脑技术自学交流平台& S% k" F, n5 m1 l3 r9 s9 o" f6 C5 L2 J
打造最好的电脑自学交流论坛) L& e1 h1 |& `- h, M
我爱电脑技术社区--打造最好的电脑技术自学交流平台! e% @; k# n6 \, X" I* d v4 m
有了ACL机制后,我们就可以在我们系统中使用动态Proxy模式来对具体对象或方法进行控制,比如,我们有一个Report类,有些用户可以读,有些用户可以写(哪些用户可以读 哪些用户可以写,已经在上面ACL里部署完成)。 我爱电脑技术社区--打造最好的电脑技术自学交流平台( W) M" D: ^; c0 O8 w2 }+ j5 w" ~; r
" W3 r& c4 ^2 Y; `- e, U5 p) Q* r打造最好的电脑自学交流论坛我爱电脑技术论坛' L; P+ L+ u& s" T. b
从Java 1.3开始, Sun提供了Dynamic Proxy API.为了使动态Proxy能够工作,第一你必须有一个Proxy接口,还要有一个继承InvocationHandler的Proxy类。
7 Q' ^7 Q) S; T
* o$ S1 o ^: E电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站在下面的例子中,我们设定有三种用户:普通人;雇员;经理.权限是这样:普通人可以读报告;雇员和经理可以修改报告。 我爱电脑技术社区--打造最好的电脑技术自学交流平台0 L" y4 }, n- Y+ B' F4 F! g
% E$ N A( H) \8 D" i: C0 x w
按通常思维,我们对于读权限,我们设计一个具备读的角色类: 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站0 P e; Y& b2 B# S
我爱电脑技术论坛7 O% o& N! ~* Q* F! v& N- d' M: U0 {
public interface IpersonRO {
. J' c8 H) e& N电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
& Y$ {( \8 f; u& W1 ]2 |# g6 K6 N电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站public String getName();
4 a+ G9 [( G$ {! b: @, b+ f5 x# S我爱电脑技术论坛电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站1 ] y) c% h0 K/ ]% Q; Y. _7 z# I
public String getAddress(); 我爱电脑技术论坛: z/ l" F" ?, U/ \. e" e) g/ M
# y: U0 c8 m* ]1 j% {电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站public String getPhoneNumber(); 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站! s* R% L3 H$ I/ c* W* l# r
& P7 a8 u" v3 h, {+ M% b
} 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站9 B* z' m. Z0 e8 O9 {) z
5 ^: s4 d6 \' A1 `; p: M6 @; j& u我爱电脑技术社区--打造最好的电脑技术自学交流平台我爱电脑技术社区--打造最好的电脑技术自学交流平台, ` F- z q$ C3 f& z
类里面都是读的方法,这是一种粗粒度访问控制,也就是说把读写权限只落实到类(对象)上,这样的话,我们还要为写的角色再建一个类,很显然这不是一个很好的方法,使用动态proxy+acl就可以实现很好的细粒度控制。 www.520diannao.com& N; s1 q6 p& B: s9 [& l
9 @2 H. c: l# j. ^' K/ X. I. x1 x
public class ReportProxy implements InvocationHandler
4 G" U. U9 ~4 @8 ^* W0 P4 lwww.520diannao.com
9 P$ m$ F- q/ o, @1 @# f我爱电脑技术论坛{ www.520diannao.com5 Y0 T8 C t1 X1 {$ a
打造最好的电脑自学交流论坛( q+ u! t' A! s* |5 c3 i
private Map map;
" {4 X1 I# N" A' ^* h打造最好的电脑自学交流论坛
# f6 }) |9 h+ w; v, j5 k! Wpublic static Object newInstance(Map map,Class[] interfaces) 我爱电脑技术社区--打造最好的电脑技术自学交流平台" H# r# _+ c g* d: u0 A4 W. N. m
我爱电脑技术论坛" g3 @7 j. o$ y" R# _9 d
{ www.520diannao.com ]/ B4 A% R# O# k' U
( E O, K: U& ]www.520diannao.comreturn Proxy.newProxyInstance(map.getClass().getClassLoader(), interfaces,new ReportProxy(map)); 打造最好的电脑自学交流论坛' o# p0 E6 y9 u0 K" `5 ]
) l+ J4 w* S5 Q+ q- x' v- ?2 }打造最好的电脑自学交流论坛} www.520diannao.com; `1 n3 _/ O* W2 w2 H% T
www.520diannao.com# x/ S; f6 i3 A. B# d; x6 \* J
public ReportProxy(Map map) 打造最好的电脑自学交流论坛% z- c/ d1 W$ f# M( |; ]
打造最好的电脑自学交流论坛 t2 ?% }3 y% f
{
9 _6 e F; k" N& ]7 m* d' w电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
w! a* Q3 `$ H# U打造最好的电脑自学交流论坛this.map = map; 打造最好的电脑自学交流论坛! u. ]+ r* S& U- j2 j& @0 L
6 N1 _$ k' n* }0 O, G2 z. }}
9 K4 [( K5 U0 r, D4 J$ m打造最好的电脑自学交流论坛我爱电脑技术社区--打造最好的电脑技术自学交流平台$ ?! o: Z: S2 P5 x9 e
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
" K8 y6 o3 H; }$ p# s m+ Q' @# r
1 _* I* w, {2 q a* O" U6 T打造最好的电脑自学交流论坛{ 我爱电脑技术论坛9 J. e3 m' t2 O# T0 a
" j' d# K3 g% x/ t1 twww.520diannao.comObject result;
1 T/ C) E; V3 t# |2 G" y打造最好的电脑自学交流论坛
7 F1 S4 G6 P8 J7 }% s' Swww.520diannao.comString methodName = m.getName(); 打造最好的电脑自学交流论坛2 \" c% n0 O: b5 p! F/ J' E8 @ S
% e+ \7 E7 z" g: ^. m5 u" _/ Owww.520diannao.comif (methodName.startsWith("get")) 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站8 n z( k, A! c6 l
; }. {$ ]1 ^) V5 N1 S5 t电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站{ 我爱电脑技术社区--打造最好的电脑技术自学交流平台3 I8 g% Y! C% ^0 }' C
: w; c h5 m1 {# m" V }' g3 |, N电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站if (!acl.checkPermission(user, "read")) return null;
8 ^: L. ?% k6 O$ Q4 R
E. V* p f- D, h+ iwww.520diannao.comString name = methodName.substring(
# n6 y' Y1 E/ ^: J打造最好的电脑自学交流论坛
$ L0 V3 [& @8 n, `% o打造最好的电脑自学交流论坛methodName.indexOf("get")+3);
1 K( O: \1 C k# o$ Qwww.520diannao.com
8 X- t! Y* P5 K5 ^我爱电脑技术论坛return map.get(name); * U$ ~" u- D- X% u8 r) v
电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站/ g3 S8 M: K3 i3 Q+ l( s# n: D
} 我爱电脑技术论坛- n! `* Y; C. x' y% @; x8 S+ f
我爱电脑技术社区--打造最好的电脑技术自学交流平台: m6 F4 e: m$ L- F
else if (methodName.startsWith("set"))
4 l) E0 M$ M* p. w+ w: v7 [2 \0 C
! t+ B5 L+ M! K8 X+ _www.520diannao.com{
?6 i+ O/ P6 K5 F0 z$ ^电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站我爱电脑技术论坛. i. K. ]* f* J/ F0 T8 v( g+ A/ b
if (!acl.checkPermission(user, "write")) return null;
( U) Z" y0 x( l) `电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
5 T! e% L" Q- ~6 D1 i. A4 r7 g我爱电脑技术论坛String name = methodName.substring( 我爱电脑技术社区--打造最好的电脑技术自学交流平台 l9 ?5 @5 I5 E; k
打造最好的电脑自学交流论坛9 V9 T# H. V4 Q6 w8 I
methodName.indexOf("set")+3); 我爱电脑技术论坛9 [0 E/ K1 U" h
www.520diannao.com& P& G+ Z4 @ G- _- ?
map.put(name, args[0]); 我爱电脑技术论坛6 }+ m# T6 v! o7 j+ }& j1 Z P
我爱电脑技术论坛! d" ~- u+ f i. B8 }1 E
return null;
. z9 Y n# s4 y* Q2 h我爱电脑技术社区--打造最好的电脑技术自学交流平台www.520diannao.com$ `% y8 f" A8 U" e$ Y+ w7 t
}
9 ?, A: s" Y3 Y8 \打造最好的电脑自学交流论坛我爱电脑技术论坛 ?# D5 e+ P- o5 ^
else if (methodName.startsWith("is"))
5 a* l6 `" k8 z/ R' P打造最好的电脑自学交流论坛
: C+ h( F" o- o我爱电脑技术社区--打造最好的电脑技术自学交流平台{ 打造最好的电脑自学交流论坛$ w) p& e2 ?! q1 J/ k
L6 r) Q' `7 {9 P& k! y" Yif (!acl.checkPermission(user, "read")) return null;
9 Y8 {3 [* f' \! S. {
$ ~; w* T1 G: c; ^我爱电脑技术社区--打造最好的电脑技术自学交流平台String name = methodName.substring( www.520diannao.com, H& G; e8 z( k- F, z! O
3 K# V# m% i+ n& _6 Z3 J0 `打造最好的电脑自学交流论坛methodName.indexOf("is")+2); www.520diannao.com0 @& A8 K3 B! [! V
) R" T- Z+ `; g8 n, Y6 y! z
return(map.get(name));
0 b8 h' H% o. a( L我爱电脑技术社区--打造最好的电脑技术自学交流平台我爱电脑技术论坛/ Q C) t% k( g
} 我爱电脑技术论坛 }' w# t! n- h t- r+ s
电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站2 Q4 r5 _" `# L5 o
return null;
+ |9 j. [7 d$ k- L7 D我爱电脑技术论坛 |& x& ?* v1 T0 q6 `
}
+ v% `6 p8 h& {+ F2 O& n5 G打造最好的电脑自学交流论坛
7 E ?4 D. w7 I1 F- C' s$ f K我爱电脑技术社区--打造最好的电脑技术自学交流平台}