Acegi是基于Spring的一个开源的安全认证框架,现在的最新版本是1.04。
, T' K' O2 h: W9 q- l7 d2 Q4 I' q! e
Acegi的特点就是有很多的过滤器:不过我们也用不到这么多的过滤器,只是可以把它们看作为一个个的模块,在用的时候加上自己用的着的即可,由于认证的流程的方面比较复杂导致它的配置很复杂,如果能摸清它的工作原理还是不太难.下面用比较顺着人思维的流程过一遍
0 J$ ]2 N- w) S0 f; E) G9 F
% |9 I+ F% u2 f- g: x1 m: g+ ~这里只列出常用的过滤器和拦载器
+ |) k/ {" V3 i8 f6 ~
1. 过滤器:
) x1 p: S) M, J! C8 `% V: \+ `
HttpSessionContextIntegrationFilter! i; i: `" U: A) s# i
authenticationProcessingFilter; b* B( P2 [1 h7 N+ r7 o
BasicProcessingFilter7 L7 |; T! U' U3 Q/ H
RememberMeProcessingFilter3 e% e7 U2 |- _, W* c: H
anonymousProcessingFilter
. U, t' `- w7 l2 p2 i/ K/ F& |exceptionTranslationFilter / J! j. P( Z& `$ L2 R/ m" f) _" j( j3 G
1 y3 `7 q3 \6 n) Y: ]" z* c/ i2 Q" Y2. 拦截器:
9 G3 s+ c/ h; {filterSecurityInterceptor(其实它是过滤器,不过把它放在这里更能说明它的功能)4 Y. x( A6 ?, ]/ U! Q! A( a! r% ]
methodSecurityInterceptor (方法拦截器)
; d6 A( y. x# ^1 v, s" H
8 q8 w: ?) M, n看着上面的用红色标出的过滤器是用来认证(表单和HTTP基本认证,当然还有别的不过这两个比较长用)它们是资源访问的入口.
: b8 }% H& r. J5 d i1 }- q
其它的过滤器是用来辅助的:
! `) A* I2 m1 q; M9 f/ Y
- F$ w9 l1 A: A. I0 P0 G2 w3 XHttpSessionContextIntegrationFilter:是用来把认证信息记录到Session中的RememberMeProcessingFilter是以cookie的形式来保存认证信息的.
6 [* Q1 p& l. o
- h3 u3 b% X- g# W% d# o% Y" F
anonymousProcessingFilter:是在匿名的时候(这时候是没有认证信息的)给这个用户分配一个匿名的认证信息
3 N" X! n. d D: w- V5 B
0 H8 S" J; l# a; E" B+ U$ d
exceptionTranslationFilter:总结一下异常并处理.在实际中选择适合程序的即可.
; r! K1 m; g7 I4 ?9 h* d2 k3 k5 I! w/ o9 N7 J0 g1 [
上面只是资源访问的入口,真正保护资源的是这两个拦截器:
2 n* v, Y( u m; P: |" M, w
' N0 F4 c% Q9 P7 ~2 T1 HfilterSecurityInterceptor:拦截URL的类(它是个过滤器)
& Z! S, y/ s+ K! k7 n2 x: O+ t* i: I. A3 ]! u* O
metohdSecurityInterceptor:拦截类中方法的调用,它们为什么要拦截呢?就是想在访问或调用这些方法之前来判断一下用户是否有访问或调用的权限,有就通过,没有就踢出.
& ^- S$ c' M4 {4 \' U3 d
/ B# b' B6 P! W, j$ U; B
除此之外,Acegi专门做了两个管理器(实际上就是两个类,为什么会用做这两个管理器,因为认证和授权都有一些的操作,这就需要专门做两个管理器了):
: [2 N) G, h6 a5 w' ~: b- f6 `用户认证管理器:authenticationManager(class= org.acegisecurity.providers.ProviderManager)
0 b, ]) T! K. ~- \( {
授权管理器:accessDecisionManager(class=org.acegisecurity.vote.AffirmativeBased)
! t S2 m: V2 l; n& ?
7 ^0 l) m! \& U4 y+ t. \
先来说认证用户,认证管理器有什么东西呢?只内置了一些提供者:这些提供者呢又是什么呢,他们是提供用户的验证身份信息的,比如从数据库或配置文件里读出用户名和密码,在用户的cookie里读出身份信息(rememberMeProcessingFilter用到的[前面讲了的,有印象吧]),或在Session里读出身份验证信息(HttpSessionContextIntegrationFilter起作用的),这里我们只说一下从数据库或配置文件里读出用户名密码来装配验证信息的,其它的配置类似可以找一下对应api在Spring里配置即可
! B' R- [3 d* Z6 l
daoAuthenticationProvider是数据库的提供者class=org.acegisecurity.providers.dao.DaoAuthenticationProvider,而它提供的服务呢又有几种,数据库和配置文件(这是Acegi的两个默认的实现)当然也可以自己实现(实现userDetailsService接口就行)
复制内容到剪贴板
代码:
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider"/>
</list>
</property>
</bean>
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService"><ref local="InMemoryDaoImpl"/></property> <!-- 配置文件中查找 -->
<property name="userDetailsService"><ref local="jdbcDaoImpl"/></property> <!--数据库中查找-->
</bean>如果用户名和密码在配置文件里可以用InMemoryDaoImpl,class=org.acegisecurity.userdetails.memory.InMemoryDaoImpl,在这个类的userMap里配置即可:javafish=java,ROLE_USER,配置了一个用户名为javafish,密码为java,用户组为ROLE_USER的用户。
, `3 k* a/ i: U v4 Q
4 C, [* P# V0 K不过最常用的还是数据库的JDBC实现(两个二选一)
Q7 b, O. ?% W2 G9 o$ Worg.acegisecurity.userdetails.jdbc.JdbcDaoImpl里面需要
usersByUsernameQuery和
authoritiesByUsernameQuery还有数据源
dataSource
1 ^8 f% ^. K3 G8 cuserByUsernameQuery:是用来通过用户名来查密码的,
1 n5 |2 i6 @" |8 @9 XauthoritiesByUsernameQuery:是用来通过用户名来查权限的,
6 I& M8 y. g. q) H: L1 k% ^' udataSource:查询数据库肯定的用数据源吧这里是用的SpringFrameWork的DataSource
5 F2 _2 c; B1 B' d6 C j( F$ {% T. U! _) r
它们查询的sql语句是有讲究的,就是查密码的时候查三个
0 p: Q9 z5 v9 k
第一个是username,
8 [& h/ B1 _8 M) b8 ~$ v' W! S x
第二个是password,
% c( ~5 |3 H5 g
第三个是是否可用,
3 a; r8 g, C; r$ S查权限的时候查两个:username和authorities(具体看例子)
复制内容到剪贴板
代码:
<bean id="InMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
javajavafish=java,ROLE_USER
</value>
</property>
</bean>
<bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
<property name="usersByUsernameQuery"> <!--通过用户名查密码-->
<value>select username,password,enabled from users where username=?</value>
</property>
<property name="authoritiesByUsernameQuery"> <!--通过用户名查权限-->
<value>select username,authority from authorities where username=?</value>
</property>
<property name="dataSource"> <!--注入数据源-->
<ref local="dataSource"/>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/test</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>javafish</value>
</property>
</bean>