第10章 Acegi安全class="tags" href="/tags/KuangJia.html" title=框架>框架
安全保护机制三步曲:认证管理器,决策管理器,过滤器链
认证和授权
一基于角色的权限控制 (Role Based Access Control RBAC)
授权-角色-用户
Java验证和授权服务(Java Authentication and Authorization Service,JAAS)是标准的谁和授权服务
二Acegi安全class="tags" href="/tags/KuangJia.html" title=框架>框架
1.Authentication对象封装了Principal(主体,通常是用户信息)和Credentials(凭证,通常中口令).
Acegi使用SecurityContext(代替HttpSession,是ThreadLocal..)来存储Authentication.(方法SecurityContextHolder.getContext.getAuthentication() )
2.有了Authentication,再通过下几个组件 ,来确保被访问资源的安全
3 安全拦截器(FilterChain,过滤器链)
认证管理器 1 决策管理器 2 运行管理器
(AuthenticationManager (AccessDecisionManager,决定是否有权限)
验证身份)
3详细讲解
3.1AuthencationManager认证管理器,该组件的任务就是对用户进行认证。认证管理器通过识别
Principal和Credentials来确定用户的身份。
Acegi提供了一个默认的Authentication的实现类ProviderManager.
ProviderManager并不直接去验证用户提供的Principal和Credentials,而是将它们委托给一个或多个AuthenticationProvider来验证,ProviderManager将逐一遍历每个AuthenticationProvider,
只要有一个Authentication Provider成功地认证了用户有,该认证过程就结束。
eg.
<class="tags" href="/tags/BEAN.html" title=bean>bean id="class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationManager" class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref class="tags" href="/tags/BEAN.html" title=bean>bean="daoAuthenticationProvider" />
<ref class="tags" href="/tags/BEAN.html" title=bean>bean="rememberMeAuthenticationProvider" />
</list>
</property>
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!-- 基于DAO验证的AuthenticationProvider -->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="daoAuthenticationProvider"
class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService" />
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<class="tags" href="/tags/BEAN.html" title=bean>bean id="rememberMeAuthenticationProvider"
class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="remember_Me" />
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!-- 使用内存DAO,实际应用时可用JdbcDao代替?? -->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="userDetailsService"
class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
admin=password,enabled,ROLE_ADMIN,ROLE_USER //格式“用户名=口令,<账户是否有效>,<角色1>,<角色2>”
test=test,enabled,ROLE_USER
guest=guest,disabled,ROLE_USER
</value>
</property>
</class="tags" href="/tags/BEAN.html" title=bean>bean>
Acegi已经提供了多个Authentication Provider可供选择:
AuthByAdapterProvider: 通过Web容器来验证用户身份。
CasAuthenticationProvider:通过CAS服务来验证用户身份,是基于单点登陆的认证方式。
DaoAuthenticationProvider:通过数据库存储的用户名口令信息来验证用户身份,这是Web应用程序最常见的认证方式
JassAuthenticationProvider:通过JAAS服务来验证用户身份。
PasswordDaoAuthenticationProvider:通过数据库认证,但是具体过程由底层数据源完成
RememberMeAuthenticationProvider:通过浏览器提供的Cookie来验证用户上次是否已经成功登陆并在有效期内,
若Cookie被接受,则通过认证。
RemoteAuthenticationProvider:通过远程服务验证用户身份.
3.2AccessDecisionManager(决策管理器)
<class="tags" href="/tags/BEAN.html" title=bean>bean id="accessDecisionManager"
class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.vote.AffirmativeBased"> //AffirmativeBased,ConsensusBased,UnamouseBased三种值
<property name="decisionVoters"> //每个投票者(RoleVoter)可以以3种方式进行投票:
//ACCESS_GRANTED赞/成票,ACCESS_DENIED拒绝票,ACCESS_ABSTAIN弃权票
<list>
<class="tags" href="/tags/BEAN.html" title=bean>bean class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.vote.RoleVoter" />
</list>
</property>
<property name="allowIfAllAbstainDecisions" value="false" /> //allowIfAllAbstainDecisions
</class="tags" href="/tags/BEAN.html" title=bean>bean>
AffirmativeBased:至少有一个投票者允许访问该资源,这是最常见的方式。
ConsensusBased:所有投票者都允许访问时,才允许访问该资源,这是最严格的方式。
UnamouseBased:如果没有投票者拒绝访问,就允许访问该资源。
这3个accessDecisionManager有一个共同的allowIfAllAbstainDecisions属性,设为true,表示如果所有的投票者都
弃权,也可以允许访问。 为flase,则都弃权,也不可以访问。
3.3FilterChain
Acegi已经提供了一系列非常有用的Filter.
1ChannelProcessingFilter:确保当前URL以指定的协议访问,例如,必须对以/secure/开头的URL使用HTTPS访问。
2ConcurrentSessionFilter:阻止同一用户在某一段时间内多次登陆。
3HttpSessionContextIntegrationFilter:由于用户的认证信息存放在Http Session 中,这个过滤器的作用就是从Session
中获得用户的认证信息,然后将其关联到当前请求中,如果没有这个过滤器,后续的请求处理就无法获得已认证的用户的身份信息。
4LogoutFilter:通过过滤特定的URL(例如/j_logout),LogoutFilter可以实现用户注销的功能。
5AuthenticationProcessingFilter:通过过滤特定的URL(例如,/j_security_check)),AuthenticationProcessingFilter可以
验证用户朐和口令,实现用户登陆的功能。 Acegi提供了多种登录的方式,除了由应用程序自身通过JDBC验证外,
还有CasProcessingFilter,JbossIntegrationFilter等。
6SecurityContextHolderAwareRequestFilter:如果应有用程序需要调用HttpServlet Request的getRemoteUser()获得用户
身份,就可以使用SecurityContextHolder Aware RequestFilter来包装原始的HttpServletRequest,它使用一个代理模式返回Acegi Authentication对象的Principal.
7 RememberMeProcessingFilter:实现雇用户登录信息的功能,使用户在一段时间内都不必输入用户名和口令,Acegi
默认采用Cookie记住用户登录信息。
8 AnonymouseProcessingFilter:如果当前用户没有登录,就将一个匿名用户身份放入SecurityContext中。
9 ExceptionTranslationFilter:捕获任何与Acegi安全相关的异常,然后根据需要将用户导向到登录页面,或者直接发送
一个403禁止访问的错误代码。
10 FilterSecurityInterceptor:最终真正保护Web资源的拦截器。
三实例
eg1.保护web资源,工程名:Spring_Acegi(通过Filter来对web页面进行保护,Filter有对URL过滤的功能,有些用户能访问/user目录,有些访问/admin目录)
知识点:Acegi有多个Filter,但我们却只需在web.xml中配置一个特殊的
Acegi Filter(FilterChainProxy)
<!-- Acegi过滤器 -->
<filter>
<filter-name>class="tags" href="/tags/ACEGI.html" title=acegi>acegiFilterChain</filter-name>
<filter-class>org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.util.FilterChainProxy</param-value>
</init-param>
</filter>
其他的Filter通过依赖注入的方式在Acegi的Spring xml中定义。(在security.xml中 过滤器链中链上...
<value>/**=httpSessionContextIntegrationFilter,logoutFilter,class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationProcessingFilter,rememberMeFilter,exceptionFilter,securityInterceptor </value>)
security.xml
<!--========================================================================
认证管理器
=========================================================================-->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationManager" class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref class="tags" href="/tags/BEAN.html" title=bean>bean="daoAuthenticationProvider" />
<ref class="tags" href="/tags/BEAN.html" title=bean>bean="rememberMeAuthenticationProvider" />
</list>
</property>
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!-- 基于DAO验证的AuthenticationProvider -->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="daoAuthenticationProvider"
class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService" />
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<class="tags" href="/tags/BEAN.html" title=bean>bean id="rememberMeAuthenticationProvider"
class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="remember_Me" />
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!-- 使用内存DAO,实际应用时可用JdbcDao代替 -->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="userDetailsService"
class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
admin=password,enabled,ROLE_ADMIN,ROLE_USER
test=test,enabled,ROLE_USER
guest=guest,disabled,ROLE_USER
</value>
</property>
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!--========================================================================
决策管理器
=========================================================================-->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="accessDecisionManager"
class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<class="tags" href="/tags/BEAN.html" title=bean>bean class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.vote.RoleVoter" />
</list>
</property>
<property name="allowIfAllAbstainDecisions" value="false" />
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!--========================================================================
过滤器链
=========================================================================-->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="filterChainProxy" class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,logoutFilter,class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationProcessingFilter,rememberMeFilter,exceptionFilter,securityInterceptor
</value> //越详细的过滤器要放前面
</property>
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!-- 基于URL的安全拦截器 -->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="securityInterceptor"
class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationManager" ref="class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationManager" />
<property name="accessDecisionManager" ref="accessDecisionManager" />
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/admin/**=ROLE_ADMIN //对应哪个文件夹 哪种角色才可以访问
/user/**=ROLE_USER
</value>
</property>
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!-- 验证用户身份 ,登陆-->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationProcessingFilter"
class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationManager" ref="class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationManager" />
<property name="class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationFailureUrl" value="/login.jsp?login_error=Login%20failed." />
<property name="defaultTargetUrl" value="/helloWorld.jsp" />
<property name="filterProcessesUrl" value="/j_login.do" />
<property name="rememberMeServices" ref="rememberMeServices" />
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!-- 登出-->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="logoutFilter" class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.ui.logout.LogoutFilter">
<!-- URL redirected to after logout -->
<constructor-arg value="/helloWorld.jsp" />
<constructor-arg>
<list>
<ref class="tags" href="/tags/BEAN.html" title=bean>bean="rememberMeServices" />
<class="tags" href="/tags/BEAN.html" title=bean>bean class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.ui.logout.SecurityContextLogoutHandler" />
</list>
</constructor-arg>
<property name="filterProcessesUrl" value="/j_logout.do" />
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!-- 记住用户登录信息 remeberMeFilter和remeberMeServices配合就实现了自动登陆功能-->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="rememberMeFilter" class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.ui.rememberme.RememberMeProcessingFilter">
<property name="class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationManager" ref="class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationManager" />
<property name="rememberMeServices" ref="rememberMeServices" />
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<class="tags" href="/tags/BEAN.html" title=bean>bean id="rememberMeServices" class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="userDetailsService" />
<property name="parameter" value="j_remember_me" />
<property name="key" value="remember_Me" />
<property name="tokenValiditySeconds" value="31536000" />
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!-- 处理登录异常或权限异常的Filter -->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="exceptionFilter" class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.ui.ExceptionTranslationFilter">
<!-- 出现AuthenticationException时的登录入口 -->
<property name="class="tags" href="/tags/AUTHENTICATION.html" title=authentication>authenticationEntryPoint">
<class="tags" href="/tags/BEAN.html" title=bean>bean class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.jsp" />
<property name="forceHttps" value="false" />
</class="tags" href="/tags/BEAN.html" title=bean>bean>
</property>
<!-- 出现AccessDeniedException时的Handler -->
<property name="accessDeniedHandler">
<class="tags" href="/tags/BEAN.html" title=bean>bean class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.ui.AccessDeniedHandlerImpl" />
<!-- 可选属性: property name="errorPage" value="/denied.html" -->
</property>
</class="tags" href="/tags/BEAN.html" title=bean>bean>
<!-- 从Session中获得用户信息并放入SecurityContextHolder -->
<class="tags" href="/tags/BEAN.html" title=bean>bean id="httpSessionContextIntegrationFilter"
class="org.class="tags" href="/tags/ACEGI.html" title=acegi>acegisecurity.context.HttpSessionContextIntegrationFilter" />
-----------------------------------------完
书中p376的图10-6为该例的结构图。
Spring的配置文件:dispatcher_servlet.xml
Acegi安全class="tags" href="/tags/KuangJia.html" title=框架>框架的配置文件:security.xml
实例2,保护Bean组件 未完~````````