Springboot2集成Shiro框架(五)使用rememberMe功能

1、什麼是rememberMe

shiro爲我們提供了rememberMe功能,也就是記住我功能,這個功能的作用很簡單,就是記住我,很多網站上都會有15天免登陸之類的功能,當我們設置了rememberMe功能後,只要登錄一次,在不手動退出登錄的情況下直接關閉瀏覽器,然後再次打開瀏覽器,仍然可以直接訪問到屬於自己的信息,這裏就實現了記住我功能。

2、rememberMe工作原理

  • 我們打開瀏覽器,進入我們的權限驗證頁面,可以看到session信息
    在這裏插入圖片描述
  • 在我們勾選了記住我後,再次登陸,如果登錄成功,則會在此位置生成記住我的一個cooike,shiro會記住我們這個識別碼,用作登陸過用戶的標記來實現user攔截器
    在這裏插入圖片描述
  • 我們查看shiro登錄的部分源碼,可以找到在AbstractRememberMeManager類的287行,部分判斷記住我源碼
    public void onSuccessfulLogin(Subject subject, AuthenticationToken token, AuthenticationInfo info) {
        //always clear any previous identity:
        forgetIdentity(subject);

        //如果記住我是true,會執行下面這段代碼
        if (isRememberMe(token)) {
            rememberIdentity(subject, token, info);
        } else {
            if (log.isDebugEnabled()) {
                log.debug("AuthenticationToken did not indicate RememberMe is requested.  " +
                        "RememberMe functionality will not be executed for corresponding account.");
            }
        }
    }

繼續深入查看,可以查看到最終調用了CookieRememberMeManager類中部分代碼實現了寫入cookie

    protected void rememberSerializedIdentity(Subject subject, byte[] serialized) {

        if (!WebUtils.isHttp(subject)) {
            if (log.isDebugEnabled()) {
                String msg = "Subject argument is not an HTTP-aware instance.  This is required to obtain a servlet " +
                        "request and response in order to set the rememberMe cookie. Returning immediately and " +
                        "ignoring rememberMe operation.";
                log.debug(msg);
            }
            return;
        }


        HttpServletRequest request = WebUtils.getHttpRequest(subject);
        HttpServletResponse response = WebUtils.getHttpResponse(subject);

        //base 64 encode it and store as a cookie:
        String base64 = Base64.encodeToString(serialized);

        Cookie template = getCookie(); //the class attribute is really a template for the outgoing cookies
        Cookie cookie = new SimpleCookie(template);
        cookie.setValue(base64);
        cookie.saveTo(request, response);
    }

3、使用rememberMe

  1. 在登錄接口上設置setRememberMe(true),我們在頁面上已經設置好,勾選選項即可
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        if (rememberMe != null) {
            token.setRememberMe(rememberMe);
        }
        try {
            // 登錄
            subject.login(token);
  1. 在ShiroController新增/user接口
    @RequestMapping("/user")
    public ReturnMap user() {
        return new ReturnMap().success().data("user可以訪問");
    }
  1. 在shiro的 shirFilter方法中新增user攔截器,

注意要寫在 “/**”, "authc"前面

 @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 攔截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 配置不會被攔截的鏈接 順序判斷
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        // 配置退出 過濾器,其中具體的退出代碼Shiro已經替我們實現了
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/user", "user");
        // 因爲目前演示頁面依附在此項目下,特爲演示頁面新增可無權限訪問,前後端分離後無需此設置
        filterChainDefinitionMap.put("/login.html", "anon");
        // <!-- 過濾鏈定義,從上向下順序執行,一般將/**放在最爲下邊 -->因爲保存在LinkedHashMap中,順序很重要
        // <!-- authc:所有url都必須認證通過纔可以訪問; anon:所有url都都可以匿名訪問-->
        filterChainDefinitionMap.put("/**", "authc");// 設置/** 爲user後,記住我纔會生效
        // 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面,前後端分離設置此爲controller返回的未登錄的接口
        // --------------------------------------------------
        // 前後端分離使用下面設置
        // shiroFilterFactoryBean.setLoginUrl("/login.html");
        shiroFilterFactoryBean.setLoginUrl("/unauthorized");// 前後端分離只需要把需要登錄返回告訴前端頁面即可
        // ---------------------------------------------------
        // 登錄成功後跳轉的鏈接,前後端分離不用設置
        // shiroFilterFactoryBean.setSuccessUrl("/index");

        // 未授權的界面
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }
  1. 頁面新增user接口按鈕
    在這裏插入圖片描述
  2. 進行測試
    • 未登錄狀態直接點擊user按鈕(無法訪問)在這裏插入圖片描述
    • 未勾選記住我,登錄成功後訪問user按鈕(可以訪問)在這裏插入圖片描述
    • 關閉瀏覽器後再打開,點擊訪問user(無權限,並且sessionid變成全新的)在這裏插入圖片描述
    • 勾選記住我登錄,可以看到user接口可以訪問,同時cookie下出現了rememberMe的cookie,有效期一年,默認httponly在這裏插入圖片描述
    • 重新打開瀏覽器,直接點擊訪問user接口(可以訪問,在這可以看到,rememberMe一直存在,sessionid變成全新的了)在這裏插入圖片描述
    • 這裏需要注意的是,即使你上次登錄的是guest用戶,選擇了記住我功能,但是仍然不能使用rememberMe功能實現guest接口的訪問,這也是shiro故意控制的一點在這裏插入圖片描述

3 、使用自定義rememberMe

  1. 在ShiroConfig類中添加cookie對象
    /**
     * Cookie 對象 用戶免登陸操作,但是需要配置filter /** 權限爲user生效
     * 
     * @return
     */
    public SimpleCookie rememMeCookie() {
        // 初始化設置cookie的名稱
        SimpleCookie simpleCookie = new SimpleCookie("boot-shiro");
        simpleCookie.setMaxAge(2592000);// 設置cookie的生效時間
        simpleCookie.setHttpOnly(true);
        return simpleCookie;
    }
  1. 添加cookie管理器bean
    /**
     * cookie 管理對象,記住我功能
     * 
     * @return
     */
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememMeCookie());
        // remeberMe cookie 加密的密鑰 各個項目不一樣 默認AES算法 密鑰長度(128 256 512)
        cookieRememberMeManager.setCipherKey(Base64.decode(ENCRYPTION_KEY));
        return cookieRememberMeManager;
    }
  1. 把cookie管理器交給SecurityManager
    /**
     * 注入 securityManager
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        securityManager.setRememberMeManager(rememberMeManager());//把cookie管理器交給SecurityManager
        return securityManager;
    }

4、總結

  1. shiro的基礎篇到此就結束了,後續會更新shiro使用ehcache和redis的總結以及遇到的問題的篇幅
  2. 需要源碼可以點擊這裏獲取!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章