• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            woaidongmao

            文章均收錄自他人博客,但不喜標題前加-[轉貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
            數據加載中……

            Acegi + Spring + Hibernate + Struts 2搭建基于角色的權限控制系統

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

            發表于 @ 2009年06月16日 22:05:00|評論(3 )|舉報|收藏

            新一篇: Quartz從入門到進階 | 舊一篇: spring整合activeMq 調試JMS

            accessmanager88 發表于2009年6月17日 12:23:36  IP:舉報
            哦,看看我的BLOG。我也在做權限管理研究。旨在把變的非常簡單,不要這么多編程和XML配置。http://blog.csdn.net/accessmanager88
            nlovea13 發表于2009年6月17日 12:38:17  IP:舉報
            挺好的,學習了!
            auuguu09 發表于2009年6月17日 14:06:15  IP:舉報
            http://www.tmbm88.cn 九九美女 http://www.mostcc.cn 448藝術網 http://www.100133.com 藝術中心 http://www.007009.com http://www.57617.com http://bq361.cn http://www.57deal.cn http://www.3330888.cn http://www.20998.com.cn http://www.cqcwct.cn http://181810.com http://www.a8bl.cn 小說 http://www.abcg008.cn 時代文章

            posted on 2009-06-17 21:24 肥仔 閱讀(1616) 評論(0)  編輯 收藏 引用 所屬分類: Web-后臺

            九九精品99久久久香蕉| 亚洲精品美女久久久久99| 免费观看成人久久网免费观看| 久久er国产精品免费观看2| 中文字幕一区二区三区久久网站| 99久久综合国产精品二区| 久久久这里有精品中文字幕| 久久精品国产亚洲AV香蕉| 久久久久久a亚洲欧洲aⅴ| 久久青青草原精品国产软件 | 69久久精品无码一区二区| 日韩精品久久久久久| 色播久久人人爽人人爽人人片AV| 久久一日本道色综合久久| 欧美一级久久久久久久大片| 久久久久久久久无码精品亚洲日韩| 精品久久人人妻人人做精品| 亚洲AV日韩精品久久久久久| 久久久久久无码国产精品中文字幕| 亚洲国产精品无码久久久秋霞2| 久久国产成人精品国产成人亚洲| 一本久久a久久精品亚洲| 无夜精品久久久久久| 久久福利片| 久久国产精品波多野结衣AV| 久久电影网一区| 久久亚洲AV成人出白浆无码国产| 天堂无码久久综合东京热| 久久久久女教师免费一区| 狠狠色丁香婷综合久久| 色欲av伊人久久大香线蕉影院| 三级韩国一区久久二区综合| 久久久久亚洲精品无码网址| 国产精品99久久不卡| 久久久精品久久久久久| 国产福利电影一区二区三区久久久久成人精品综合| 日本久久久久亚洲中字幕| 色综合久久中文字幕无码| 亚洲综合日韩久久成人AV| 国产成年无码久久久免费| 久久丫精品国产亚洲av不卡|