安全永远是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 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) 就可以了.