<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    cuiyi's blog(崔毅 crazycy)

    記錄點滴 鑒往事之得失 以資于發展
    數據加載中……

    SpringMVC+MyBatis - 5 Security-Shiro-01

    文章摘錄處

    安全認證框架-APACHE SHIRO研究心得

    最近因為項目需要,研究了一下Apache Shiro安全認證框架,把心得記錄下來。(原創by:西風吹雨) 

    Apache Shrio是一個安全認證框架,和Spring Security相比,在于他使用了和比較簡潔易懂的認證和授權方式。其提供的native-session(即把用戶認證后的授權信息保存在其自身提供Session中)機制,這樣就可以和HttpSession、EJB Session Bean的基于容器的Session脫耦,到到和客戶端應用、Flex應用、遠程方法調用等都可以使用它來配置權限認證。 

    1、sessionMode 
    在普通的WEB項目中,我們可以選擇使用native session或者是HttpSession,通過設置securityManager的sessionMode參數為http或native即可。 

    2、realm
    我們可以基于jdbc,ldap,text,activeDirectory,jndi等多種方式來獲取用戶基本信息,角色信息,權限信息等。只需要在securityManager中指定使用相應的realm實現即可,其在這各方面都提供了對應的缺省實現,比如我們常用的基于數據庫表的形式來配置用戶權限信息,就可以使用其缺省實現的jdbcRealm(org.apache.shiro.realm.jdbc.JdbcRealm)。

    當然,如果認證信息來自于多方面,多個不同的來源(比如來自兩個庫中,或者一個數據庫,一個是ldap,再配上一個缺省的基于文本的測試用等等),我們可以為securityManager指定realms參數,即把這一組安全配置都配置上。各個具體的realm實現提供了方法來獲取用戶基本信息、角色、權限等。 realm的授權信息可以存放在Cache中,Cache的名稱可以通過設置其authorizationCacheName參數指定。 

    3、緩存 
    目前Shrio缺省提供了基于ehCache來緩存用戶認證信息和授權信息的實現。只需要配置 org.apache.shiro.web.mgt.DefaultWebSecurityManager 這個 cacheManager并設置給SecurityManager即可。

    如果項目中已經存在使用的ehCacheManager配置(org.springframework.cache.ehcache.EhCacheManagerFactoryBean),DefaultWebSecurityManager則可以指定使用現有的ehCacheManager,如果不指定,它將自行使用缺省配置創建一個。

    同時,也可以設置cacheManagerConfigFile參數來指定ehCache的配置文件。 下例中的shiro.authorizationCache是用來存放授權信息的Cache,我們在配置realm(如myRealm或jdbcReaml)時,把authorizationCacheName屬性設置shiro.authorizationCache來對應。 

    ehcache.xml  
    <ehcache>

    <diskStore path="java.io.tmpdir/tuan-oauth"/>



    <defaultCache
    maxElementsInMemory="10000"
    eternal
    ="false"
    timeToIdleSeconds
    ="120"
    timeToLiveSeconds
    ="120"
    overflowToDisk
    ="false"
    diskPersistent
    ="false"
    diskExpiryThreadIntervalSeconds
    ="120"
    />

    <!-- We want eternal="true" (with no timeToIdle or timeToLive settings) because Shiro manages session
    expirations explicitly. If we set it to false and then set corresponding timeToIdle and timeToLive properties,
    ehcache would evict sessions without Shiro's knowledge, which would cause many problems
    (e.g. "My Shiro session timeout is 30 minutes - why isn't a session available after 2 minutes?"
    Answer - ehcache expired it due to the timeToIdle property set to 120 seconds.)

    diskPersistent=true since we want an enterprise session management feature - ability to use sessions after
    even after a JVM restart. 
    -->
    <cache name="shiro-activeSessionCache"
    maxElementsInMemory
    ="10000"
    eternal
    ="true"
    overflowToDisk
    ="true"
    diskPersistent
    ="true"
    diskExpiryThreadIntervalSeconds
    ="600"/>

    <cache name="shiro.authorizationCache"
    maxElementsInMemory
    ="100"
    eternal
    ="false"
    timeToLiveSeconds
    ="600"
    overflowToDisk
    ="false"/>

    </ehcache>

    當我們把securityManager的sessionMode參數設置為native時,那么shrio就將用戶的基本認證信息保存到缺省名稱為shiro-activeSessionCache 的Cache中 

    org.apache.shiro.web.mgt.DefaultWebSecurityManager 在sessionMode參數設置為native時,缺省使用的是DefaultWebSessionManager來管理Session,該管理類缺省使用的是使用MemorySessionDAO基于內存來保存和操作用戶基本認證信息。

    如果系統內的用戶數特別多,我們需要使用CacheSessionDao來基于Cache進行操作,因此,這里需要顯示配置一個sessionManager(org.apache.shiro.web.session.mgt.DefaultWebSessionManager),并配置該sessionManager的sessionDao為CacheSessionDao(org.apache.shiro.session.mgt.eis.CachingSessionDAO,需用其實現類org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO)。

    配置CacheSessionDao時,我們可以指定屬性activeSessionsCacheName的名稱來替換掉缺省名 shiro-activeSessionCache。我們再把該sessionManager配置給DefaultWebSecurityManager就可以了。 

    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        
    <property name="cacheManager" ref="cacheManager" />
        
    <property name="sessionMode" value="native" />
        
    <!-- Single realm app. If you have multiple realms, use the 'realms' property 
            instead. 
    -->
        
    <property name="realm" ref="myRealm" />
        
    <property name="sessionManager" ref="sessionManager" />
    </bean>

    <bean id="sessionManager"
        class
    ="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        
    <property name="sessionDAO" ref="sessionDAO" />
    </bean>

    <bean id="sessionDAO"
        class
    ="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
        
    <property name="activeSessionsCacheName" value="shiro-activeSessionCache" />
    </bean>
      
    從以上我們可以看出 
    a、我們可以指定sessionManager的sessionDao,在某些情況下,我們也可以通過實現自定義的sessionDao來把用戶認證信息保存在memcache,mongodb,ldap,database中,達到和其他應用共享用戶認證信息的目的,以此達到SSO的目的(當然,sessionId得一致,這個屬于我們可以在應用商定怎么設定一致的sessionId的問題)。 

    b、cacheManager我們也可以自己實現一個,可以根據應用情況來考慮,比如存放在memcache中之類。 

    4、配置 
    Web項目中,普通的web項目可以采用ini文件來對shiro進行配置?;趕pring的項目可以采用和Spring集成的方式配置。 基于Spring集成的Web項目的基本配置文件如下: 
     
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context
    ="http://www.springframework.org/schema/context"
        xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation
    ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"
    >

        
    <!-- ========================================================= Shiro Core 
            Components - Not Spring Specific ========================================================= 
    -->

        
    <!-- Shiro's main business-tier object for web-enabled applications (use 
            DefaultSecurityManager instead when there is no web environment) 
    -->
        
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            
    <property name="cacheManager" ref="cacheManager" />
            
    <!-- Single realm app. If you have multiple realms, use the 'realms' property 
                instead. 
    -->
            
    <property name="sessionMode" value="native" />
            
    <property name="realm" ref="myRealm" />
        
    </bean>

        
    <!-- Let's use some enterprise caching support for better performance. You 
            can replace this with any enterprise caching framework implementation that 
            you like (Terracotta+Ehcache, Coherence, GigaSpaces, etc 
    -->
        
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
            
    <!-- Set a net.sf.ehcache.CacheManager instance here if you already have 
                one. If not, a new one will be creaed with a default config: 
    -->
            
    <property name="cacheManager" ref="ehCacheManager" />
            
    <!-- If you don't have a pre-built net.sf.ehcache.CacheManager instance 
                to inject, but you want a specific Ehcache configuration to be used, specify 
                that here. If you don't, a default will be used.: <property name="cacheManagerConfigFile" 
                value="classpath:some/path/to/ehcache.xml"/> 
    -->
        
    </bean>

        
    <!-- Used by the SecurityManager to access security data (users, roles, 
            etc). Many other realm implementations can be used too (PropertiesRealm, 
            LdapRealm, etc. 
    -->
        
    <bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
            
    <property name="name" value="jdbcRealm" />
            
    <property name="dataSource" ref="dataSource" />
            
    <property name="credentialsMatcher">
                
    <!-- The 'bootstrapDataPopulator' Sha256 hashes the password (using the 
                    username as the salt) then base64 encodes it: 
    -->
                
    <bean class="org.apache.shiro.authc.credential.Sha256CredentialsMatcher">
                    
    <!-- true means hex encoded, false means base64 encoded -->
                    
    <property name="storedCredentialsHexEncoded" value="false" />
                    
    <!-- We salt the password using the username, the most common practice: -->
                    
    <property name="hashSalted" value="true" />
                
    </bean>
            
    </property>
            
    <property name="authorizationCacheName" value="shiro.authorizationCache" />
        
    </bean>

        
    <bean id="myRealm" class="org.apache.shiro.realm.text.IniRealm"
            init-method
    ="init">
            
    <property name="name" value="myRealm" />
            
    <property name="authorizationCacheName" value="shiro.authorizationCache" />
            
    <property name="resourcePath" value="classpath:config/myRealm.ini" />

        
    </bean>

        
    <!-- ========================================================= Shiro Spring-specific 
            integration ========================================================= 
    -->
        
    <!-- Post processor that automatically invokes init() and destroy() methods 
            for Spring-configured Shiro objects so you don't have to 1) specify an init-method 
            and destroy-method attributes for every bean definition and 2) even know 
            which Shiro objects require these methods to be called. 
    -->
        
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

        
    <!-- Enable Shiro Annotations for Spring-configured beans. Only run after 
            the lifecycleBeanProcessor has run: 
    -->
        
    <bean
            
    class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
            depends-on
    ="lifecycleBeanPostProcessor" />
        
    <bean
            
    class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            
    <property name="securityManager" ref="securityManager" />
        
    </bean>


        
    <!-- Secure Spring remoting: Ensure any Spring Remoting method invocations 
            can be associated with a Subject for security checks. 
    -->
        
    <bean id="secureRemoteInvocationExecutor"
            class
    ="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
            
    <property name="securityManager" ref="securityManager" />
        
    </bean>

        
    <!-- Define the Shiro Filter here (as a FactoryBean) instead of directly 
            in web.xml - web.xml uses the DelegatingFilterProxy to access this bean. 
            This allows us to wire things with more control as well utilize nice Spring 
            things such as PropertiesPlaceholderConfigurer and abstract beans or anything 
            else we might need: 
    -->
        
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            
    <property name="securityManager" ref="securityManager" />
            
    <property name="loginUrl" value="/login" />
            
    <property name="successUrl" value="/index" />
            
    <property name="unauthorizedUrl" value="/unauthorized" />
            
    <!-- The 'filters' property is not necessary since any declared javax.servlet.Filter 
                bean defined will be automatically acquired and available via its beanName 
                in chain definitions, but you can perform overrides or parent/child consolidated 
                configuration here if you like: 
    -->
            
    <!-- <property name="filters"> <util:map> <entry key="aName" value-ref="someFilterPojo"/> 
                </util:map> </property> 
    -->
            
    <property name="filterChainDefinitions">
                
    <value>
                    /login = authc
                    /account = user
                    /manage = user,roles[admin]
                
    </value>
            
    </property>
        
    </bean>
    </beans>
      
    5、基于url資源的權限管理 
    我們可以簡單配置在shiroFilter的filterChainDefinitions中,也可以考慮通過一個文本文件,我們讀入內容后設置進去。或者通過Ini類來裝入Ini文件內容,到時取出urls的部分來設置給shiroFilter的filterChainDefinitions。也可以把這部分數據存入數據庫表中,到時讀出一個Map來設置給shiroFilter的filterChainDefinitionsMap屬性。 

    6、url的配置 
    authc是認證用戶(rememberMe的用戶也必須再次登錄才能訪問該url),配置成user才能讓rememberMe用戶也可以訪問。 

    7、rememberMe Cookie的處理 
    Shiro有一套缺省機制,由CookieRememberMeManager實現。其有一個SimpleCookie類,保存對應的用戶信息等。

    每次保存時,系統把SimpleCookie的信息設置好之后,先用DefaultSerializer把其用jvm缺省序列化方式序列化成byte[],然后再用cipherService(缺省是aes加密算法)來加密該byte[],最后用Base64.encodeToString(serialized)壓縮成一個字符串,再寫入名稱為rememberMe的Cookie中。 

    讀取時,通過把該rememberMe Cookie的內容用byte[] decoded = Base64.decode(base64)解壓出該byte[],再用cipherService解密,最后用DefaultSerializer反序列化出來該SimpleCookie類。 

    如果我們有自定義的rememberMe Cookie需要處理,特別是在和其他網站一起SSO,通過訪問主域的Cookie來獲取記錄的用戶信息時,我們需要重新實現rememberMeManager(可以考慮繼承AbstractRememberMeManager),和根據實際用的序列化方式Serializer來實現一個(比如考慮通用性,用json方式序列化)。

    在Spring配置中,配置好RememberMeManager,裝配上sericerlizer和cipherService(根據實際情況選用適當的加密算法),最后把rememberMeManager設置給DefaultWebSecurityManager即可。如果非常簡單的cookie,可以直接實現RememberMeManager的幾個接口方法也行


    【Apache Shiro in Spring】自定義filterChainDefinitions和Realm
    文章出處

    在Spring Context中定義shiroFilter(org.apache.shiro.spring.web.ShiroFilterFactoryBean)時需要為其filterChainDefinitions property賦值,這個屬性是個chainName-to-chainDefinition map of chain definitions,用于為URL定義過濾策略。

    filterChainDefinitions是一個set method,他調用setFilterChainDefinitionMap(section),FilterChainDefinitionMap是個Field。

    比如,這是我定義的:

    /404.htm = anon /main!main.html = anon /**.html = perms[myPerm_1]


    在這里引用一下某前輩總結的chainDefinition,如下:

    rest:比如/admins/user/**=rest[user],根據請求的方法,相當于/admins/user/**=perms[user:method] ,其中method為post,get,delete等。

    port:比如/admins/user/**=port[8081],當請求的url的端口不是8081是跳轉到schemal://serverName:8081?queryString,其中schmal是協議http或https等,serverName是你訪問的host,8081是url配置里port的端口,queryString是你訪問的url里的?后面的參數。

    perms:比如/admins/user/**=perms[user:add:*],perms參數可以寫多個,多個時必須加上引號,并且參數之間用逗號分割,比如/admins/user/**=perms["user:add:*,user:modify:*"],當有多個參數時必須每個參數都通過才通過,想當于isPermitedAll()方法。

    roles:比如/admins/user/**=roles[admin],參數可以寫多個,多個時必須加上引號,并且參數之間用逗號分割,當有多個參數時,比如/admins/user/**=roles["admin,guest"],每個參數通過才算通過,相當于hasAllRoles()方法。

    anon:比如/admins/**=anon 沒有參數,表示可以匿名使用。

    authc:比如/admins/user/**=authc表示需要認證才能使用,沒有參數

    authcBasic:比如/admins/user/**=authcBasic沒有參數表示httpBasic認證

    ssl:比如/admins/user/**=ssl沒有參數,表示安全的url請求,協議為https

    user:比如/admins/user/**=user沒有參數表示必須存在用戶,當登入操作時不做檢查


    一般情況下,我們可以將模塊作為一個授權單位,例如:

    /blog!**.html = user

    偶爾也會有將每一個URL作為一個授權單位進行控制,例如:

    /blog!doAddNewArticle.html = authc,perms[addArticle]

    但是URL的數量讓人頭疼,也許可以每開發一個功能的時候打開XML文件寫入URL然后同步到SVN,或者我們也可以找一個人專門做這些事情,無論是添加、刪除功能還是修改方法名都通知這個人去做...換位思考一下,我不希望我是這個人...

    所以我要把這些URL放在數據庫進行管理。我要把他們統統Query出來放到filterChainDefinitions里。
    我需要裝配一個Bean,實際上他是一個org.springframework.beans.factory.FactoryBean<Section>的實現。

    <bean id="chainFilterBuff"   class="king.common.ChainFilterBuff">
        <property name="filterChainDefinitions">
        /404.htm = anon
        /main!main.html = anon
        </property>
    </bean>

    然后將其注入:

    <bean id="shiroFilter1" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value="/main!main.html" />
        <property name="successUrl" value="/main!main.html" />
        <property name="unauthorizedUrl" value="/unAuthorized.htm" />
        <property name="filterChainDefinitionMap" ref="chainFilterBuff" />
    </bean>


    Java代碼中implements FactoryBean<Ini.Section>并實現需要Override的method,關鍵是getObject這個method:

    private String filterChainDefinitions;
    @Override
    public Section getObject() throws Exception {
        Ini ini = new Ini();
        ini.load(filterChainDefinitions);   //先載入XML中定義好的chain
        Ini.Section section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
        /*
         *  省略讀取步驟
         *  繼續加入數據庫中的chain
         *  section.put("/**", "authc, roles[admin]");
         
    */
                                                                                                                                                                                                                                                                                                                                           
        return section;
    }

    等等,這些僅僅是定義了權限。

    我們需要在用戶訪問這些URL的時候去驗證一下用戶是否具備當前URL權限。
    所以我定義了(事實上我們必須定義一個Realm,ShiroFilterFactoryBean需要SecurityManager,而我們使用的SecurityManager的實現類DefaultWebSecurityManager則需要一個Realm!):

    <bean id="shiroDataBaseRealm" class="king.security.KingMainRealm">

    并且Override了接口定義的method:

    public class KingMainRealm extends AuthorizingRealm {
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo( //授權
                PrincipalCollection principals) {
            UserBean _user = (UserBean) principals.fromRealm(getName()).iterator().next();
            SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();
                    /*
                     * 省略
                     
    */
            return authInfo;
        }
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo( //認證
                AuthenticationToken token) throws AuthenticationException {
            UserBean user = new UserBean();
            UsernamePasswordToken userToken = (UsernamePasswordToken)token;
            user.setUserName(userToken.getUsername());
            user.setPassword(userToken.getPassword());
                                                      
            return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
        }
    }

    若已定義了需要請求的URL,用戶登錄時doGetAuthorizationInfo會被調用,剩下的就是為每一個用戶管理這些權限了。

    也許我們可以創建角色關聯多個權限,用戶關聯多個角色,類似這樣的設置不同的層次。
    按你喜歡的方式去做吧 

    posted on 2014-07-11 09:38 crazycy 閱讀(2255) 評論(0)  編輯  收藏 所屬分類: JavaEE技術

    主站蜘蛛池模板: 浮力影院亚洲国产第一页| 97在线免费视频| 亚洲影视自拍揄拍愉拍| 亚洲AV无码AV男人的天堂| 亚洲无码精品浪潮| 尤物永久免费AV无码网站| 免费国产黄线在线观看| 97在线观看永久免费视频| 久久久国产精品福利免费| 国产精品偷伦视频免费观看了| 亚洲中文精品久久久久久不卡| 亚洲国产精品xo在线观看| 亚洲美女免费视频| 亚洲精品动漫在线| 亚洲国产成人久久77| 亚洲色图视频在线观看| 午夜亚洲www湿好大| 亚洲理论精品午夜电影| 亚洲嫩草影院在线观看| 亚洲一级毛片在线播放| 在线亚洲午夜片AV大片| 激情小说亚洲图片| 一个人晚上在线观看的免费视频| 2022免费国产精品福利在线| 久久久久久噜噜精品免费直播| 99久久99这里只有免费的精品| a视频在线观看免费| 麻花传媒剧在线mv免费观看| 在线观看特色大片免费视频| 国产一区二区免费在线| 国产精品亚洲高清一区二区| 亚洲国产精品婷婷久久| 亚洲综合av一区二区三区不卡| 污视频网站在线免费看| 精品四虎免费观看国产高清午夜| 国产黄色免费网站| 亚洲av日韩av欧v在线天堂| 亚洲av无码片在线播放| 亚洲国产日韩综合久久精品| 一级毛片在线完整免费观看| 亚洲黄色免费在线观看|