並不複雜,只需4步搞定Shiro集成redis實現會話共享

個人公衆號: MarkerHub,Java網站: https://markerhub.com

更多精選文章請點擊:Java筆記大全.mdjava

小Hub領讀:

集羣的分佈式場景中,咱們須要把衆多服務的會話狀態保持一致,常見的就是把會話信息保存到redis中實現共享,那麼你知道shiro集成redis實現會話共享有多簡單嗎?真的只須要4步!nginx


在一些分佈式場景中,好比一個簡單負載均衡場景,一個nginx,反向代理到兩個tomcat,tomcat運行這一樣的項目,那麼這時候,服務的會話須要共享,由於咱們已經使用了shiro來完成咱們的認證受權邏輯,那麼shiro完成登陸以後,如何讓另一個服務同時也是登陸狀態呢?git

咱們延用上篇文章的項目代碼,使用兩個端口8080、8081分別啓動項目。github

有些同窗不知道怎麼用idea同一個項目分別啓動兩個端口,其實很簡單,只須要在Run/Debug ConfigurationsVM options上,指定啓動端口-Dserver.port=8081便可!
web

ok,分別啓動8080和8081項目以後,登陸8080項目,而後訪問8081,發現8081未登陸!圖示以下:redis

那麼,如何才能8080登陸以後,8081也同時完成登陸呢?spring

特殊解決方式

其實在負載均衡集羣中,有些人是這樣解決問題,給ip指定服務,好比某個用戶請求通過nginx反向代理到8080服務,那麼nginx上指定ip_hash:依據ip分配方式,那麼這個用戶就一直訪問同一個服務,不會訪問到8081服務,因此用戶就一直是訪問統一服務,因此在用戶看來,他就一直是登陸狀態的。數據庫

可是,這是有缺陷的,由於ip和服務綁定了,加入這個服務掛了以後,是不會轉發到其餘服務,因此對這用戶來講,就訪問異常。segmentfault

因此咱們須要使用更經常使用的負載均衡策略,好比輪詢、權重等。緩存

回顧shiro的架構與組件

ok,進入正題,shiro作會話共享,會話信息能夠存儲到內存,數據庫,或者緩存中間件中,這裏咱們使用一個經常使用的緩存中間件Redis來保存咱們的會話信息,那麼,咱們就須要shiro集成redis。

能夠回顧一下以前咱們介紹過的shiro的總體架構:
圖片

上面與會話或緩存相關的組件有:

  • Session Manager 會話管理器
  • Session DAO 會話 DAO,將session保存到數據庫、緩存等
  • Cache Manager 緩存管理器,權限認證的緩存、用戶及權限信息的緩存等

若是隻是作會話共享,只是改寫Session DAO好像也是能夠的,我以前試過,不過既然shiro已經集成redis,那麼數據啥的最好也一塊兒共享吧,防止出現緩存不一致的狀況。按照這個邏輯,其實就是重寫這3個組件就好了。

shiro-redis整合步驟

那麼,有什麼已經寫好的shiro集成redis整合項目嘛?

這裏給你們介紹一個

https://github.com/alexxiyang/shiro-redis/
# 文檔
https://github.com/alexxiyang/shiro-redis/blob/master/docs/README.md
# 或者
http://alexxiyang.github.io/shiro-redis/

readme.md上有詳細的教程,這裏咱們直接使用Spring boot starter方式,由於須要寫的代碼少,直接寫寫配置就好。

第一步:導入shiro-redis的starter包

<dependency>
    <groupId>org.crazycake</groupId>
    <artifactId>shiro-redis-spring-boot-starter</artifactId>
    <version>3.2.1</version>
</dependency>

能夠看下shiro-redis-spring-boot-starter源碼:

能夠看出,已經包含了shiro-spring-boot-web-startershiro-redis整合包了,因此以前項目中整合進來的shiro-spring-boot-web-starter能夠註釋掉了。

第二步,根聽說明,readme裏面說,若是你沒有自定義建立SessionManager or SessionsSecurityManager,那麼會自動給你建立,集成完成。可是咱們自定義了realm,因此SecurityManager仍是必需要自定義的。

  • com.markerhub.config.ShiroConfig
@Configuration
public class ShiroConfig {

    @Autowired
    RedisSessionDAO redisSessionDAO;

    @Autowired
    RedisCacheManager redisCacheManager;

    @Bean
    AccountRealm accountRealm() {
        return new AccountRealm();
    }

    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();

        // inject redisSessionDAO
        sessionManager.setSessionDAO(redisSessionDAO);
        return sessionManager;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(AccountRealm accountRealm, SessionManager sessionManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(accountRealm);

        //inject sessionManager
        securityManager.setSessionManager(sessionManager);

        // inject redisCacheManager
        securityManager.setCacheManager(redisCacheManager);

        return securityManager;
    }

    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

        // logged in users with the 'admin' role
        chainDefinition.addPathDefinition("/admin/**", "authc, roles[admin]");

        // logged in users with the 'document:read' permission
        chainDefinition.addPathDefinition("/docs/**", "authc, perms[document:read]");

        chainDefinition.addPathDefinition("/login", "anon");
        chainDefinition.addPathDefinition("/doLogin", "anon");

        // all other paths require a logged in user
        chainDefinition.addPathDefinition("/**", "authc");
        return chainDefinition;
    }
}

相比以前的配置,多了配置了個SessionManager,而後對應配置中注入sessionManager和redisCacheManager。好像項目就已經能夠運行啦。

登陸成功以後查看redis中的數據效果以下:

說明咱們的會話信息已經保存到redis中啦。而後咱們再換個端口8081啓動項目,發現8080登陸成功以後,8081服務也是登陸成功狀態。

第三步、根據需求調整參數,能夠在配置文件中調整的參數我貼出來:

  • application.yml
shiro-redis:
  enabled: true
  redis-manager:
    host: 127.0.0.1:6379

ok,shiro-redis已經整合完畢,是否是挺簡單的哈。

注意點

使用這個整合包,有個注意點,若是你使用了spring-boot-devtools做爲自動熱加載重啓,那麼自動重啓後會報錯,解決方法也簡單,官方已經給出瞭解決方案:

If you are using shiro-redis with spring-boot-devtools. Please add this line to resources/META-INF/spring-devtools.properties (Create it if there is no this file):

restart.include.shiro-redis=/shiro-[\w-\.]+jar

因此,第四步:只須要在resources新建一個文件夾META-INF,而後新建文件spring-devtools.properties,內容爲:

restart.include.shiro-redis=/shiro-[\\w-\\.]+jar

效果以下:

結束語

好了,今天先講到這裏吧,shiro系列的文章已經發了幾篇了,後面還有一篇集成單點登陸的,而後就完結了哈。這裏是MarkerHub,我是小Hub呂一明,快去星標置頂個人公衆號吧!


(完)

推薦閱讀

Java筆記大全.md

太讚了,這個Java網站,什麼項目都有!https://markerhub.com

這個B站的UP主,講的java真不錯!

相關文章
相關標籤/搜索