搭建基于角色的权限控制系统

 安全永远是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代码
    <?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="[email protected]" />
    </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="[email protected]" />
    <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>
    view plaincopy to clipboardprint?
    <?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="[email protected]" />
    </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="[email protected]" />
    <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>

    <?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="[email protected]" />
    </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="[email protected]" />
    <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, 增加安全控制过滤链

    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>
    view plaincopy to clipboardprint?
    <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>

    <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代理

    Xml代码
    <!-- 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>
    view plaincopy to clipboardprint?
    <!-- 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安全控制拦截器 -->
    <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

    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);
    }
    }
    view plaincopy to clipboardprint?
    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);
    }
    }

    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) 就可以了.



文章转载自网管之家:http://www.bitscn.com/pdb/java/200806/144038.html

猜你喜欢

转载自xxs673076773.iteye.com/blog/1148125
今日推荐