[简介]
Acegi Security System 是一种功能强大并易于使用的替代性方案,使您不必再为 Java
企业应用程序编写大量的安全代码。虽然它专门针对使用 Spring 框架编写的应用程序,但是任何类型的 Java 应用程序都没有理由不去使用
Acegi。
Acegi Security System 使用安全过滤器来提供企业应用程序的身份验证和授权服务。该框架提供了不同类型的过滤器,可以根据应用程序的需求进行配置。您将在本文后面了解到 安全过滤器的不同类型
;现在,只需注意可以为如下任务配置 Acegi 安全过滤器:
- 在访问一个安全资源之前提示用户登录。
- 通过检查安全标记(如密码),对用户进行身份验证。
- 检查经过身份验证的用户是否具有访问某个安全资源的特权。
- 将成功进行身份验证和授权的用户重定向到所请求的安全资源。
- 对不具备访问安全资源特权的用户显示 Access Denied 页面。
- 在服务器上记录成功进行身份验证的用户,并在用户的客户机上设置安全 cookie。使用该 cookie 执行下一次身份验证,而无需要求用户登录。
- 将身份验证信息存储在服务器端的会话对象中,从而安全地进行对资源的后续请求。
- 在服务器端对象中构建并保存安全信息的缓存,从而优化性能。
- 当用户退出时,删除为用户安全会话而保存的服务器端对象。
- 与大量后端数据存储服务(如目录服务或关系数据库)进行通信,这些服务用于存储用户的安全信息和 ECM 的访问控制策略。
正如这个列表显示的那样,Acegi 的安全过滤器允许您执行保护企业应用程序所需的几乎任何事情。
[基础工作]
在你的Web应用的lib中添加Acegi下载包中的acegi-security.jar
[web.xml]
在web.xml配置
<filter>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<filter-class>
org.acegisecurity.util.FilterToBeanProxy
</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>
org.acegisecurity.util.FilterChainProxy
</param-value>
</init-param>
</filter>
<filter-mapping>限定了FilterToBeanProxy
的URL匹配模式
,
<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>的HttpSessionEventPublisher
用于发布HttpSessionApplicationEvents
和HttpSessionDestroyedEvent
事件给spring的applicationcontext
。
<listener>
<listener-class>
org.acegisecurity.ui.session.HttpSessionEventPublisher
</listener-class>
</listener>
[applicationContext-acegi-security.xml]
applicationContext-acegi-security.xml文件配置
FilterChainProxy
会按顺序来调用这些filter,使这些filter能享用Spring ioc的功能
, CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON定义了url比较前先转为小写, PATTERN_TYPE_APACHE_ANT定义了使用Apache ant的匹配模式
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter, logoutFilter, authenticationProcessingFilter,
basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,
switchUserProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>
定义数据源为调用tomcat容器数据源 登入验证时需要获取数据源连接数据库
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>java:/comp/env/jdbc/test</value></property>
</bean>
Acegi提供了不同的AuthenticationProvider的实现,如:
DaoAuthenticationProvider 从数据库中读取用户信息验证身份
AnonymousAuthenticationProvider 匿名用户身份认证
RememberMeAuthenticationProvider 已存cookie中的用户信息身份认证
AuthByAdapterProvider 使用容器的适配器验证身份
CasAuthenticationProvider 根据Yale中心认证服务验证身份, 用于实现单点登陆
JaasAuthenticationProvider 从JASS登陆配置中获取用户信息验证身份
RemoteAuthenticationProvider 根据远程服务验证用户身份
RunAsImplAuthenticationProvider 对身份已被管理器替换的用户进行验证
X509AuthenticationProvider 从X509认证中获取用户信息验证身份
TestingAuthenticationProvider 单元测试时使用
认证管理 ,从数据库中读取用户信息验证身份
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider"/>
</list>
</property>
</bean>
daoAuthenticationProvider
进行简单的基于数据库的身份验证。DaoAuthenticationProvider
获取数据库中的账号密码并进行匹配,若成功则在通过用户身份的同时返回一个包含授权信息的Authentication对象
,否则身份验证失败,抛出一个AuthenticatiionException
。
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService"><ref local="jdbcDaoImpl"/></property>
<property name="passwordEncoder"><ref local="passwordEncoder"/></property>
<property name="userCache"><ref local="userCache"/></property>
</bean>
jdbcDaoImpl
用于在数据中获取用户信息
<bean id="jdbcDaoImpl" class="com.milesup.acegi.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
<property name="rolePrefix"><value>ROLE_</value></property>
</bean>
passwordEncoder
使用加密器对用户输入的明文进行加密。Acegi提供了三种加密器:
1 : PlaintextPasswordEncoder—默认,不加密,返回明文.
2 : ShaPasswordEncoder—哈希算法(SHA)加密
3 : Md5PasswordEncoder—消息摘要(MD5)加密
使用加密器对用户输入的明文进行加密 为MD5加密方式
<bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>
缓存用户和资源相对应的权限信息。每当请求一个受保护资源时,daoAuthenticationProvider
就会被调用以获取用户授权信息
。如果每次都从数据库获取的话,那代价很高,对于不常改变的用户和资源信息来说,最好是把相关授权信息缓存起来。
userCache提供了两种实现: NullUserCache
和EhCacheBasedUserCache
, NullUserCache
实际上就是不进行任何缓存,EhCacheBasedUserCache
是使用Ehcache来实现缓功能。
<!-- 缓存管理 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
<!-- 缓存用户和资源相对应的权限信息 -->
<bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="cacheManager"/>
</property>
<property name="cacheName">
<value>userCache</value>
</property>
</bean>
<bean id="userCache" class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
<property name="cache"><ref local="userCacheBackend"/></property>
</bean>
该过滤器用来处理在系统认证授权过程中抛出的异常
<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property>
</bean>
一个没有进行身份验证的用户试图访问受保护的资源验证是否授权 Exception Translation Filter(ETF)
<bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl"><value>/login.jsp</value></property>
<property name="forceHttps"><value>false</value></property>
</bean>
登入验证
成功进入main.jsp页面 ,失败跳转到/login.jsp?login_error=1 ,登入url为 /j_acegi_security_check, Authentication Processing Filter(APF)
authenticationFailureUrl
定义登陆失败时转向的页面
defaultTargetUrl
定义登陆成功时转向的页面
filterProcessesUrl
定义登陆请求的页面
rememberMeServices
用于在验证成功后添加cookie信息
<bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="authenticationFailureUrl"><value>/login.jsp?login_error=1</value></property>
<property name="defaultTargetUrl"><value>/main.jsp</value></property>
<property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property>
<property name="rememberMeServices"><ref local="rememberMeServices"/></property>
</bean>
用于处理HTTP头的认证信息,如从Spring远程协议 (如Hessian和Burlap)或普通的浏览器如IE,Navigator的HTTP头
中获取用户 信息,将他们转交给通过authenticationManager 属性装配的认证管理器。如果认证成功,会将一个Authentication对象放到会话中 ,否则,如果认证失败,会将控制转交给认证入口点 (通过 authenticationEntryPoint属性装配)
<!-- 用于处理HTTP头的认证信息 -->
<bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="authenticationEntryPoint"><ref local="basicProcessingFilterEntryPoint"/></property>
</bean>
<!-- 通过向浏览器发送一个HTTP401(未授权)消息,提示用户登录 -->
<bean id="basicProcessingFilterEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
<property name="realmName"><value>Milesup Realm</value></property>
</bean>
注销 退出验证 跳转到/login.jsp
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg value="/login.jsp"/><constructor-arg>
<list>
<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
</bean>
经过投票
机制来决定是否可以访问某一资源(URL
或方法
)。allowIfAllAbstainDecisions为false时如果有一个或以上的decisionVoters投票通过,则授权通过。可选的决策机制有ConsensusBased和UnanimousBased
roleVoter
必须是以rolePrefix设定的value开头的权限才能进行投票,如 ROLE_
<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
<property name="rolePrefix">
<value>ROLE_</value>
</property>
</bean>
<!-- 组件管理授权过程 决策管理器-->
<bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
<ref bean="roleVoter"/>
</list>
</property>
</bean>
过滤器安全拦截器 是否认证,是否有权限访问受保护的资源
在执行转向url前检查objectDefinitionSource
中设定的用户权限信息。首先,objectDefinitionSource
中定义了访问URL需要的属性信息(这里的属性信息仅仅是标志,告诉accessDecisionManager
要用哪些voter来投票)。然后,authenticationManager
掉用自己的provider来对用户的认证信息进行校验。最后,有投票者根据用户持有认证和访问url需要的属性,调用自己的voter来投票,决定是否允许访问。
<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property>
<property name="objectDefinitionSource">
<value>
PATTERN_TYPE_APACHE_ANT
/user.jsp=ROLE_ADMIN
/admin=ROLE_ADMIN
</value>
</property>
</bean>
[login.jsp]
<form action="/j_acegi_security_check" method="post" >
<table>
<tr>
<td width="140" height="22" align="right">用户名</td>
<td width="47%" align="left"><input name="j_username" type="text" class="inputstyle" id="j_username"></td>
<td align="left" nowrap><div class="loginmeon"> </div></td>
</tr>
<tr>
<td width="140" height="22" align="right">密 码</td>
<td width="47%" align="left"><input name="j_password" type="password" class="inputstyle" id="j_password" size="21"></td>
</tr> <tr>
<td height="60" colspan="3" align="center" valign="middle">
<input type="submit" name="imageField2" value="登入"></td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
[JdbcDaoImpl.java]
public class JdbcDaoImpl extends org.acegisecurity.userdetails.jdbc.JdbcDaoImpl {
private String anonymousRoleName = "ROLE_ANONYMOUS";
private Log logger = LogFactory.getLog(JdbcDaoImpl.class);
private PreparedStatement userPstmt;
private PreparedStatement rolePstmt;
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException, DataAccessException {
UserDetails user = findUserByName(userName);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return user;
}
private UserDetails findUserByName(String userName) {
Connection connection = null;
ResultSet rsUser = null;
ResultSet rsRole = null;
UserDetails user = null;
String logonName = null;
String password = null;
String roleName = null;
int status = -1;
boolean enabled = false;
Vector roles = null;
GrantedAuthority[] rolesArray = null;
try {
connection = getDataSource().getConnection();
userPstmt = connection
.prepareStatement("select * from users where user_NAME=?");
userPstmt.setString(1, userName);
rsUser = userPstmt.executeQuery();
if (rsUser.next()) {
logonName = rsUser.getString("USER_NAME");
password = rsUser.getString("PASSWORD");
status = rsUser.getInt("STATUS");
if (status == 1)
enabled = true;
} else {
return null;
}
rolePstmt = connection
.prepareStatement("SELECT ROLE.NAME Role FROM ROLE, users_ROLES, users WHERE ROLE.ID= user_ROLES.FK_ROLES and users.user_NAME=?");
rolePstmt.setString(1, userName);
rsRole = rolePstmt.executeQuery();
roles = new Vector();
while (rsRole.next()) {
roleName = getRolePrefix() + rsRole.getString("Role");
roles.add(new GrantedAuthorityImpl(roleName));
}
rolesArray = new GrantedAuthority[roles.size() + 1];
int index = 0;
for (index = 0; index < roles.size(); index++)
rolesArray[index] = (GrantedAuthority) roles.get(index);
rolesArray[index] = new GrantedAuthorityImpl(anonymousRoleName);
user = new User(logonName, password, enabled, true, true, true,
rolesArray);
} catch (SQLException e) {
logger.fatal("", e);
} finally {
try {
//关闭数据库连接的程序
} catch (SQLException sqlx) {
logger.fatal("", sqlx);
} catch (NullPointerException x) {
logger.fatal("", x);
}
}
return user;
}
}
分享到:
相关推荐
Acegi学习笔记--Acegi详解Acegi学习笔记--Acegi详解Acegi学习笔记--Acegi详解Acegi学习笔记--Acegi详解Acegi学习笔记--Acegi详解
Acegi学习笔记(JAVA系统安全编程时用到),我就用到了Acegi,真的太牛了。
acegi学习笔记
acegi配置,让你更好的合理的了解acegi是什么
一个使用Acegi身份认证框架的笔记 可以节省你的时间 方便快速学会使用
最近因为公司的需要,用acegi进行权限控制,简单总结了一下,和大家分享
里边包括了 Acegi安全系统介绍.doc、Acegi使用.pdf、acegi学习笔记.doc、实战acegi.pdf、以及自己整理的 acegi的认证过滤器.rar
关于Acegi的安全框架,里面有Acegi的实例,讲述得挺清楚的,
acegi-context配置文件 博文链接:https://lib.iteye.com/blog/165980
我在配置spring security2.0是的工作笔记 很有启发性
常見程式演算,電腦圖學入門,設計模式,C 語言,GTK,C++,Qt3,Qt4,,Java (上),Java (下),JSP/Servlet,JSF,Ajax,JUnit,Struts,Spring,Hibernate,Acegi
Spring源代码解析1:IOC容器.doc Spring源代码解析2:IoC容器在Web容器中的启动.doc Spring源代码解析3:Spring JDBC .doc Spring源代码解析4:Spring MVC .doc ...Spring源代码解析10:Spring Acegi框架授权的实现.doc
ext学习笔记一 小试iBatis RIA(Rich Internet Application)的现状和未来 Java应用中域名解析不过期的解决方法 Java编程那些事儿45—数组使用示例1 一步步熟悉OFBiz 用Java做客户端调用.NET写...