- 浏览: 124898 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
愿景十月天:
两个表之间咋地关联呢?
hibernate 中HQL语句查询学习 -
xurichusheng:
LZ应该列出使用的jar包co.transport.jms.J ...
Spring的JMSTemplate的使用 -
lin_zy:
错误是显示在前台了,但问题还是美解决
Ajax4jsf 和 <h:message> 一起使用时候的问题 -
greemranqq:
<value>jdbc:mysql://local ...
Spring+JPA+MySQL的配置文件 -
successfulroof:
wyyacyy 写道可以详细介绍一下,a4j:commandL ...
动态自增表格rich:dataTable
安全永远是WEB应用系统必须面对的头等大事, 也是最头疼的事, 其实安全系统就只包括两个问题: 认证和授权.
以前做些网站系统, 安全检测逻辑都在放在须要安全控制的代码前面, 这样做有很多不好的地方, 重复多次的编码就不用说了, 代码移植性, 重用性都得不到体现, 安全检测逻辑要永远和业务逻辑放在一起.
那么, 能不能够在进入方法前就调用一些安全检测? 其实Spring AOP就是这个思想, 那么又如何实现安全检测呢? Spring Acegi Security 框架就是做这个事情.
本文主要是讨论下在已有的SSH系统中, 如何使用Acegi作为安全框架实现基于角色的权限控制(Role Based Access Control RBAC) , 本文主要是以Java 5注解的形式来配置安全框架, 大大减化配置和操作.
本文的主要参考资料: <Spring 2.0 核心技术与最佳实践> 第10章 (Spring Acegi 安全框架)
<精通Spring 2.X -- 企业应用开发详解> 第17章 (使用Acegi 实施应用系统安全)
acegi-security-1.0.6 官方文档
说明: 本文介绍的是RBAC, 在官方文档的基础上有所扩展或改动, 以更适合WEB应用系统. 其实我觉得大多数的网站基于角色已经足够了, 一般都没必要基于权限.
文章开始:
一. 下载所要的软件或JAR包:
我的相关配置是: Java 5, Tomcat 5.5.26, Struts 2.0.11, Spring 2.5.1, Hibernate 3.2, Acegi 1.0.6
二. 建立相关的数据库:
数据表: 用户信息表User: id, enable, user_name, user_pass, email_box
角色信息表RoleInfo: id, role_name, role_title, descp
用户与角色关联表(用户与角色是多对多关系)UserRole: user_id, user_name, role_id, role_name
并在这三个表中插入相关的数据, 我是定义了两种角色(role_name): ROLE_USER, ROLE_ADMIN
和三个用户, 一个用户角色为: ROLE_USER, ROLE_ADMIN
另一个用户角色为: ROLE_USER
第三个没有角色.
二. 修改配置文件:
其实对Acegi框架的应用难点就在配置文件, 所以要特别注意了:
在 src 建立Acegi的配置文件: acegi-security.xml 当然这个文件的名称是可以任意的.
acegi-security.xml 说白了就是配置: 安全拦截器, 认证管理器, 决策管理器.
其内容如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- ========================= 认证管理器 ========================= --> <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> <property name="providers"> <list> <ref bean="daoAuthenticationProvider" /> <ref bean="rememberMeAuthenticationProvider" /> </list> </property> </bean> <!-- 基于DAO验证的AuthenticationProvider --> <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> <property name="userDetailsService" ref="userDetailsService" /> </bean> <bean id="userDetailsService" class="org.ymcn.security.AcegiUserDeitailsService"> <property name="userDao" ref="userDao" /> <property name="userRoleDao" ref="userRoleDao" /> </bean> <bean id="rememberMeAuthenticationProvider" class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider"> <property name="key" value="obullxl@163.com" /> </bean> <bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices"> <property name="userDetailsService" ref="userDetailsService" /> <property name="parameter" value="j_remember_me" /> <property name="key" value="obullxl@163.com" /> <property name="tokenValiditySeconds" value="31536000" /> </bean> <!-- ========================= 决策管理器 ========================= --> <bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased"> <property name="decisionVoters"> <list> <ref bean="roleVoter" /> </list> </property> <!-- 是否全部弃权就通过 --> <property name="allowIfAllAbstainDecisions" value="false" /> </bean> <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter"> <property name="rolePrefix" value="ROLE_" /> </bean> <!-- ========================= 过滤器链 ========================= --> <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,rememberMeFilter,exceptionFilter,securityInterceptor </value> </property> </bean> <bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter" /> <bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter"> <!-- 登录退出后的URL --> <constructor-arg value="/" /> <constructor-arg> <list> <ref bean="rememberMeServices" /> <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" /> </list> </constructor-arg> <!-- 登录退出的URL --> <property name="filterProcessesUrl" value="/j_logout.j" /> </bean> <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"> <property name="authenticationManager" ref="authenticationManager" /> <!-- 登录失败后的URL --> <property name="authenticationFailureUrl" value="/login.jsp?msg=%E6%97%A0%E6%95%88%E7%9A%84%E7%94%A8%E6%88%B7%E5%90%8D%E6%88%96%E5%8F%A3%E4%BB%A4" /> <!-- 登录成功后的URL --> <property name="defaultTargetUrl" value="/user/cmd.jsp" /> <!-- 登录的URL --> <property name="filterProcessesUrl" value="/j_login.j" /> <property name="rememberMeServices" ref="rememberMeServices" /> </bean> <bean id="rememberMeFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter"> <property name="authenticationManager" ref="authenticationManager" /> <property name="rememberMeServices" ref="rememberMeServices" /> </bean> <bean id="exceptionFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"> <!-- 出现AuthenticationException时的登录入口 --> <property name="authenticationEntryPoint"> <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"> <property name="loginFormUrl" value="/login.jsp" /> <property name="forceHttps" value="false" /> </bean> </property> <!-- 出现AccessDeniedException时的Handler --> <property name="accessDeniedHandler"> <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl"> <property name="errorPage" value="/denied.jsp" /> </bean> </property> </bean> <bean id="securityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"> <property name="authenticationManager" ref="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 /cart/previeworder*=ROLE_USER </value> </property> </bean> </beans>
在上面的配置文件中, 红色部分要特别注意, 其余的内容都差不多了.
<bean id="userDetailsService" class="org.ymcn.security.AcegiUserDeitailsService">
<property name="userDao" ref="userDao" />
<property name="userRoleDao" ref="userRoleDao" />
</bean>
在整个应用的安全控制中, 我们唯一要编写代码的类就是: org.ymcn.security.AcegiUserDeitailsService
就连登录和登出的代码也不要了.
三. 修改 web.xml, 增加安全控制过滤链
<filter> <filter-name>acegiFilterChain</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> <filter-name>acegiFilterChain</filter-name> <url-pattern>*.j</url-pattern> </filter-mapping>
注意: 这个过滤器一定要在MVC转发过滤器的前面!!!!
四. 在 applicationContext.xml 中增加 Acegi安全控制拦截器 和 Spring的自动代理功能实现AOP代理
<!-- Acegi安全控制拦截器 --> <bean id="serviceSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"> <property name="validateConfigAttributes" value="true" /> <property name="authenticationManager" ref="authenticationManager" /> <property name="accessDecisionManager" ref="accessDecisionManager" /> <property name="objectDefinitionSource"> <bean class="org.acegisecurity.intercept.method.MethodDefinitionAttributes"> <property name="attributes"> <bean class="org.acegisecurity.annotation.SecurityAnnotationAttributes" /> </property> </bean> </property> </bean> <!-- 利用Spring的自动代理功能实现AOP代理 --> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <list> <value>transactionInterceptor</value> <value>serviceSecurityInterceptor</value> </list> </property> <property name="beanNames"> <list> <value>userService</value> <value>mailService</value> </list> </property> </bean>
五. 编写在利用Acegi框架唯一要我们编写的类 AcegiUserDeitailsService.java
package org.ymcn.security; import java.util.List; import org.acegisecurity.GrantedAuthority; import org.acegisecurity.GrantedAuthorityImpl; import org.acegisecurity.userdetails.UserDetails; import org.acegisecurity.userdetails.UserDetailsService; import org.acegisecurity.userdetails.UsernameNotFoundException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.dao.DataAccessException; import org.ymcn.dao.UserDao; import org.ymcn.dao.UserRoleDao; import org.ymcn.model.User; import org.ymcn.model.UserRole; public class AcegiUserDeitailsService implements UserDetailsService { private final Log LOG = LogFactory.getLog(AcegiUserDeitailsService.class); /* 依赖注入 */ private UserDao userDao; private UserRoleDao userRoleDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void setUserRoleDao(UserRoleDao userRoleDao) { this.userRoleDao = userRoleDao; } /* 用户所有的权限 */ //private final List<GrantedAuthority> grantedAuthList = new ArrayList<GrantedAuthority>(6); private GrantedAuthority[] grantedAuthArray; public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException { if(LOG.isDebugEnabled()) { LOG.debug("Loading UserDetails of userName: " + userName); } /* 取得用户 */ User user = userDao.getUserByName(userName); if(user == null) { LOG.warn("UserDetails load failed: No such UserRole with userName: " + userName); throw new UsernameNotFoundException("User name is not found."); } /* 取得所有用户权限 */ List<UserRole> userRoleList = userRoleDao.getUserRoleByUserName(userName); if(userRoleList == null || userRoleList.size() == 0) { LOG.warn("UserRole load failed: No such UserRole with userName: " + userName); throw new UsernameNotFoundException("UserRole is not found."); } /* 取得用户的所有角色 */ int size = userRoleList.size(); grantedAuthArray = new GrantedAuthority[size]; int j = 0; for(int i = 0; i < size; i++) { UserRole userRole = userRoleList.get(i); if(userRole != null) { this.grantedAuthArray[j++] = new GrantedAuthorityImpl(userRole.getRoleName().toUpperCase()); } } LOG.info("UserName: " + userName + " loaded successfully."); return new org.acegisecurity.userdetails.User(userName, user.getUserPass(), true, true, true, true, this.grantedAuthArray); } }
六. 在业务逻辑代码中利用Java 5注释实现安全控制
@Secured({"ROLE_USER"})
void sendSimpleMail(Long userId);
@Secured({"ROLE_ADMIN"})
void sendAttachmentMail() throws Exception;
其实就是在需要安全控制的方法前加上: @Secured({"角色名"}), 非常的简单
七. 整个工作完成
Acegi框架完全是一种可插拔式的, 完全可以在原有的系统中加个一个配置文件, 和在每个方法前加上: @Secured({"角色名"}) 就可完成.
上面的 AcegiUserDeitailsService.java 中的有 UserDao, UserRoleDao, 我想一看就知道它们是干什么的了, 这完全取决于个人的实现, 与Acegi无关, 它仅仅只要返回一个 return new org.acegisecurity.userdetails.User(userName, user.getUserPass(),
true, true, true, true, this.grantedAuthArray) 就可以了.
评论
发表评论
-
使用spring查找hibernate映射文件
2008-09-12 14:02 1494LocalSessionFactoryBean有好几个属性用来 ... -
JdbcTemplate - 查询
2008-09-11 15:29 3445使用JdbcTemplate进行查询时,可以使用queryFo ... -
spring执行定时任务
2008-09-08 14:57 1306package timerTask; import java ... -
Spring+JPA+MySQL的配置文件
2008-06-25 10:17 3027一直在整合spring+hibernate,今天整合一下JPA ... -
Spring 事务管理
2008-06-25 09:20 1407通常建议采用声明式事务管理。声明式事务管理的优势非常明显:代码 ... -
spring和quartz进行定时邮件发送
2008-06-22 18:45 1152一 发送邮件的基类: public abstract cla ... -
Spring的JMSTemplate的使用
2008-06-21 18:48 68931:在web.xml文件中配置一个spring用的上下文: & ... -
利用 Spring IoC 配置 EHCache
2008-05-29 12:01 1231利用 Spring IoC 配置 EHCache 在 Spri ... -
Quartz与Spring结合时如何动态更新Job的启动时间
2008-05-28 12:14 1297动态更新的Java类如下: import org.quartz ...
相关推荐
本篇文章将探讨如何使用Acegi、Spring、Hibernate和Struts2这四大组件共同构建一个基于角色的权限控制系统(Role-Based Access Control, RBAC),以确保系统的安全性。 首先,我们需要理解认证和授权这两个基本的...
struts + spring + hibernate + velocity + ajax + jotm + acegi
Struts2+Spring+Hibernate权限系统是一个经典的Java Web开发架构,用于构建高效、可扩展的企业级应用程序。这个架构结合了三个强大的开源框架:Struts2作为MVC(模型-视图-控制器)框架,Spring作为服务层管理和依赖...
Spring Security、Spring 3.0、Hibernate 3.5 和 Struts2 是四个在Java开发领域广泛应用的开源框架,它们各自在不同的层面上为应用程序提供服务。本文将深入探讨这些框架的功能、集成方式以及如何构建一个基于它们的...
Struts2、Spring、Hibernate和MySQL是Java Web开发中常用的技术栈,它们组合起来可以构建一个功能完善的权限管理系统。下面将分别介绍这四个组件及其在权限管理中的应用。 1. **Struts2**:Struts2是一个基于MVC...
Acegi、Hibernate、Spring 和 JSF 是 Java 企业级开发中的四大重要框架,它们共同构建了一个强大、灵活且可扩展的Web应用程序体系结构。在这个"Acegi+Hibernate+Spring+JSF例子"中,我们可以看到这四个框架如何协同...
本项目以"权限控制(struts2+hibernate+spring+struts-menu+valuelist)"为主题,采用一系列成熟的技术栈来实现这一目标。下面我们将深入探讨这些技术及其在项目中的应用。 首先,Struts2作为MVC框架,负责处理HTTP...
在本系统中,Spring负责管理Struts2和Hibernate的bean,以及权限控制等业务逻辑组件,实现了服务层的解耦和模块化。 再者,Hibernate作为一款持久化框架,简化了Java应用程序与数据库之间的交互。它支持对象-关系...
在本示例中,Acegi被用来扩展权限系统,可能包含了自定义的认证和授权规则,以及与Struts2的集成,确保只有经过验证的用户才能访问特定的资源。 Hibernate3是一个对象关系映射(ORM)框架,它简化了数据库操作,...
Struts2、Spring3.02、Spring Security3和Hibernate3.6是Java Web开发中的四大框架,它们各自承担着不同的职责,共同构建了一个高效、稳定的后端架构。以下将详细解析这四个组件及其整合应用。 **Struts2** 是一个...
此外,Spring的安全模块(Spring Security,前身是Acegi)可以用于更复杂的权限控制,但这里可能只是实现了基本的身份验证。 Hibernate3是一个对象关系映射(ORM)框架,它简化了Java应用与数据库之间的交互。在...
Struts2、Spring4和Hibernate5是Java Web开发中的三个核心框架,它们分别负责MVC模式中的表现层、业务层和服务层。这三个框架的整合,通常被称为SSH整合,能够实现高效、灵活且松耦合的Web应用开发。下面将详细阐述...
在本文中,我们将深入探讨一个基于Struts2、Spring4和Hibernate5的权限管理系统——"crm_ssh"项目。这个项目展示了如何将这三个流行的技术栈整合在一起,为业务逻辑提供一个强大的支持平台。 **Struts2** 是一个...
Struts2.0+spring2.0+hibernate3.1 ACEGI应用示例
本文将详细介绍如何利用Acegi安全框架(现称为Spring Security)结合SSH(Struts + Spring + Hibernate)技术栈来实现一个动态的角色权限管理系统。 #### Acegi安全框架简介 Acegi安全框架,后更名为Spring ...
SSH(Struts+Spring+Hibernate)是Java企业级应用开发中常见的技术栈,它提供了强大的模型-视图-控制器(MVC)架构支持,以及持久层和业务层的优秀解决方案。本教程通过构建一个简单的电子公告板示例,揭示了SSH组合...
"Struts+Spring+Hibernate" 是一种经典的Java Web开发架构,通常被称为SSH框架。这个登陆系统是基于这三个框架构建的,下面将详细解释每个框架及其在登录系统中的作用。 **Struts** Struts是一个开源的MVC(Model-...