權限框架——shiro的使用看這篇就夠了(進階篇)

關於shiro的學習推薦官網:

在這裏插入圖片描述
官網鏈接地址: http://shiro.apache.org/

關於shiro的一些簡單配置,如何整合springboot快速啓動,快速使用請看上篇文章
地址:https://blog.csdn.net/weixin_42083036/article/details/105701439

本篇文章旨在,提高shiro的性能,用戶體驗,以及增加shiro的適用範圍

1、提高性能篇

1、Redis整合Cachemanager
  • 使用原因:上一篇講到每一次鑑權,shiro都需要查詢一次數據庫,對應頻繁的接口訪問與sql查詢,性能和響應速度都極度下降所以我們需要使用緩存。
  • 步驟
    1、加依賴
<!-- shiro+redis緩存插件 -->
     <dependency>
			<groupId>org.crazycake</groupId>
			<artifactId>shiro-redis</artifactId>
			<version>3.1.0</version>
		</dependency>

        2、 配置bean

 	//使用自定義的cacheManager   綁定securityManager
   securityManager.setCacheManager(cacheManager());
  /**
     * 配置redisManager
     *
     */
    public RedisManager getRedisManager(){
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("localhost");
        redisManager.setPort(6379);
        return redisManager;
    }


    /**
     * 配置具體cache實現類
     * @return
     */
    public RedisCacheManager cacheManager(){
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(getRedisManager());
         //設置過期時間,單位是秒,20s,
        redisCacheManager.setExpire(20);

        return redisCacheManager;
    }

        3、安裝Redis(已安裝的可以忽略)

注:出現問題

class java.lang.String must has getter for field: authCacheKey or id\nWe need a field to identify this Cache Object in Redis. So you need to defined an id field which you can get unique id to identify this principal. For example, if you use UserInfo as Principal class, the id field maybe userId, userName, email, etc. For example, getUserId(), getUserName(), getEmail(), etc.\nDefault value is authCacheKey or id, that means your principal object has a method called \"getAuthCacheKey()\" or \"getId()\""

原因:原先自定義授權返回獲取的是用戶名稱(String)類型,當你綁定了緩存,返回類型變成了對象,造成原因是由於緩存需要一個唯一鍵作爲緩存索引,所以默認返回了對象。

解決方案:修改自定義realm

doGetAuthorizationInfo 方法
原有:
	String username = (String)principals.getPrimaryPrincipal();
	User user = userService.findAllUserInfoByUsername(username);

改爲

	User newUser = (User)principals.getPrimaryPrincipal();
    User user = userService.findAllUserInfoByUsername(newUser.getUsername());

doGetAuthenticationInfo方法
原有:
return new SimpleAuthenticationInfo(username, user.getPassword(), this.getClass().getName());

改爲
return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName());

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

此時你會發現除了第一次訪問控制檯打印了用戶信息,說明進行了sql查詢,第二次以後訪問控制檯沒有打印相關信息說明沒有進行sql查詢,直接走的緩存查詢相關信息。

2、Redis整合SessionManager
1、爲什麼?
  • 重啓應用,用戶無感覺,不影響用戶使用
  • 解決多節點sessionid無法共用問題

步驟:

  • 創建自定義持久化session
/**
 * 自定義session持久化
 * @return
 */
public RedisSessionDAO redisSessionDAO(){
    RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
    redisSessionDAO.setRedisManager(getRedisManager());
    //設置持久化超時時間  默認和下面這句話時間設置一樣  
    // customSessionManager.setGlobalSessionTimeout(200000);

    return redisSessionDAO;
}
  • 綁定SessionManager
//設置自定義session持久化
customSessionManager.setSessionDAO(redisSessionDAO());

中途可能會報錯,如下:

2020-04-29 15:05:40.541 ERROR 11376 --- [nio-8088-exec-2] org.crazycake.shiro.RedisSessionDAO      : serialize session error. session id=boyuan104f486347614bf4b704079c3e53bbdd

很明顯是由於實體沒有實現序列化接口Serializable導致的。
注:需要把所有相關聯的實體全部序列化,否則還是會報錯。

  • 緩存id過期時間的設置
設置一個過期時間
 redisSessionDAO.setExpire(180000);

不設置默認和sessionmanager設置時間一致
在這裏插入圖片描述

3、shiroConfig 常用bean類配置
1、管理生命週期的
  • LifecycleBeanPostProcessor :管理shiro一些bean的生命週期 即bean初始化 與銷燬
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
	return new LifecycleBeanPostProcessor();
}
2、開啓shiro註解使用的
  • AuthorizationAttributeSourceAdvisor:加入註解的使用,不加入這個AOP註解不生效(shiro的註解 例如 @RequiresGuest)
@Bean
 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
  AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
}
3、掃描所有的Advistor(通知器)的
  • DefaultAdvisorAutoProxyCreator: 用來掃描上下文尋找所有的Advistor(通知器), 將符合條件的Advisor應用到切入點的Bean中,需要在LifecycleBeanPostProcessor創建後纔可以創建
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public  DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
}

注:因爲這個類是掃描所有的bean的,需要被生命週期管理類所管理,必須在生命週期類生成後再注入。所以需要使用@DependsOn(“lifecycleBeanPostProcessor”)

4、shiro自定義sessionid

Shiro 默認的sessionid生成 類名 SessionIdGenerator
創建一個類,實現 SessionIdGenerator 接口的方法

/**
 * 自定義session持久化
 * @return
 */
public RedisSessionDAO redisSessionDAO(){
    RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
    redisSessionDAO.setRedisManager(getRedisManager());

    //設置sessionid生成器
    redisSessionDAO.setSessionIdGenerator(new CustomSessionIdGenerator());

    return redisSessionDAO;
}

總結

分佈式應用下的鑑權方式

1、演進方式
  • 單體應用——>多節點
    session——>分佈式session(在每個服務都保存一個sessionid)
    好處維護簡單
    缺點:資源佔用嚴重,容易造成混亂

  • 分佈式應用——>輕量(訪問量<10W)
    UUID 使用UUID生產token保存在緩存中
    好處:較傳統模式鑑權,服務器的資源佔用更少,實現簡單
    缺點:由於比較簡易,無法處理複雜的鑑權業務,只能用於訪問量<10w的項目

  • 微服務

  • JWT(json web token)
    JWT 自定義加密簽名等等
    好處:生成的憑證無法篡改。安全性更高
    缺點:
    1、JWT默認不加密,但可以加密。生成原始令牌後,可以使用改令牌再次對其進行加密。
    2、當JWT未加密方法是,一些私密數據無法通過JWT傳輸。
    3、JWT不僅可用於認證,還可用於信息交換。善用JWT有助於減少服務器請求數據庫的次數。
    4、JWT的最大缺點是服務器不保存會話狀態,所以在使用期間不可能取消令牌或更改令牌的權限。也就是說,一旦JWT簽發,在有效期內將會一直有效。
    5、JWT本身包含認證信息,因此一旦信息泄露,任何人都可以獲得令牌的所有權限。爲了減少盜用,JWT的有效期不宜設置太長。對於某些重要操作,用戶在使用時應該每次都進行進行身份驗證。
    6、爲了減少盜用和竊取,JWT不建議使用HTTP協議來傳輸代碼,而是使用加密的HTTPS協議進行傳輸。

  • author 2.0
    通過請求授權模式進行獲取相應的用戶信息
    好處:安全可靠,獲取的用戶數據沒有隱私信息
    缺點:編碼困難,成本較高

沒有100%可靠的算法,暴力破解,窮舉
解決方案:

  1. 限制時間內ip登錄錯誤次數
  2. 增加圖形驗證碼,不能過於簡單,常用的OCR可以識別驗證碼

建議:微服務裏面,特別是對C端用戶的應用,不要做過於複雜的權限校驗,特別是影響性能這塊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章