SpringBoot集成Shiro實(shí)現(xiàn)多數(shù)據(jù)源認(rèn)證授權(quán)與分布式會(huì)話(一)

項(xiàng)目背景

在最近重構(gòu)后的項(xiàng)目中使用了springboot+shiro的技術(shù)棧,shiro是一個(gè)強(qiáng)大且易用的Java安全框架,執(zhí)行身份驗(yàn)證、授權(quán)、密碼學(xué)和會(huì)話管理.shiro包含三個(gè)核心組件subject,securityManager和realm.subject即當(dāng)前操作用戶,代表了當(dāng)前用戶的安全操作,shiro底層使用了threadlocal來(lái)存取當(dāng)前用戶的subject.
securityManager則是管理所有用戶的安全操作,屬于框架的核心組件,shiro通過(guò)它來(lái)管理內(nèi)部組件與提供各種服務(wù)。
realm充當(dāng)了shiro與數(shù)據(jù)之間的橋梁,實(shí)質(zhì)上就是封裝好的一個(gè)安全相關(guān)的DAO。
本系統(tǒng)使用了shiro來(lái)處理用戶的身份認(rèn)證與權(quán)限校驗(yàn)。

具體實(shí)現(xiàn)

首先在項(xiàng)目的pom文件中引入shiro的核心包.

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${org.apache.shiro-version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${org.apache.shiro-version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${org.apache.shiro-version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${org.apache.shiro-version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-aspectj</artifactId>
            <version>${org.apache.shiro-version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-quartz</artifactId>
            <version>${org.apache.shiro-version}</version>
        </dependency>

然后創(chuàng)建一個(gè)shiro的配置類ShiroConfiguration,shiro使用了過(guò)濾器shiroFilter來(lái)作為入口點(diǎn),用于攔截需要安全控制的請(qǐng)求.

    /**
     * ShiroFilterFactoryBean 處理攔截資源文件問(wèn)題。
     * Filter Chain定義說(shuō)明 1、一個(gè)URL可以配置多個(gè)Filter,使用逗號(hào)分隔 
       2、當(dāng)設(shè)置多個(gè)過(guò)濾器時(shí),全部驗(yàn)證通過(guò),才視為通過(guò)
     * 3、部分過(guò)濾器可指定參數(shù),如perms,roles
     */
    @Bean
    public ShiroFilterFactoryBean shirFilter() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必須設(shè)置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager());
        // 如果不設(shè)置默認(rèn)會(huì)自動(dòng)尋找Web工程根目錄下的"/login.jsp"頁(yè)面
        shiroFilterFactoryBean.setLoginUrl("/login.html");
        // 登錄成功后要跳轉(zhuǎn)的鏈接
        shiroFilterFactoryBean.setSuccessUrl("/admin/index.html");
        // 未授權(quán)界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
        //Shiro自定義認(rèn)證過(guò)濾器
        Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();//獲取filters
        filters.put("authc", new CustomerFormAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(filters);
        // 攔截器.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //攔截的,從上向下順序執(zhí)行,匹配成功就不再繼續(xù)往下走
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/img/favicon.ico", "anon,noSessionCreation");
        filterChainDefinitionMap.put("/templates/system/public/**", "anon");
        filterChainDefinitionMap.put("/vertifyCode/**", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/toLogin", "anon");
        // <!-- authc:所有url都必須認(rèn)證通過(guò)才可以訪問(wèn); anon:所有url都都可以匿名訪問(wèn)-->
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

設(shè)置系統(tǒng)的sessionid,框架默認(rèn)為: JSESSIONID,可改成其他的如token.

    @Bean
    public SimpleCookie wapsession() {
        SimpleCookie simpleCookie = new SimpleCookie("token");
        simpleCookie.setMaxAge(2592000);
        return simpleCookie;
    }

接下來(lái)配置cookie管理器.

    @Bean
    public SimpleCookie rememberMeCookie() {
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        simpleCookie.setMaxAge(2592000);
        simpleCookie.setHttpOnly(true);
        return simpleCookie;
    }

提供了記住我(RememberMe)的功能.

    @Bean
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        byte[] cipherKey = Base64.decode("4AvVhmFLUs0KTA3Kprsdag==");
        cookieRememberMeManager.setCookie(rememberMeCookie());
        cookieRememberMeManager.setCipherKey(cipherKey);
        return cookieRememberMeManager;
    }

配置securityManager安全管理器.

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager() {
        logger.info("注入Shiro的Web過(guò)濾器-->securityManager", ShiroFilterFactoryBean.class);
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setAuthenticator(authenticator());
        //設(shè)置多Realm,用于獲取認(rèn)證憑證
        Collection<Realm> realms = new ArrayList<>();
        realms.add(appShiroRealm());
        realms.add(pcShiroRealm());
        realms.add(thirdPathShiroRealm());
        securityManager.setRealms(realms);
        //注入緩存管理器
        //securityManager.setCacheManager(ehCacheManager());
        //注入會(huì)話管理器
        securityManager.setSessionManager(sessionManager());
        //注入Cookie(記住我)管理器(remenberMeManager)
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

定義數(shù)據(jù)源Realm.

    /*
     * @describe 自定義AppRealm
     * @param []
     * @return com.hongsui.win.home.controller.admin.web.realm.AppShiroRealm
    */
    @Bean
    public AppShiroRealm appShiroRealm() {
        AppShiroRealm appShiroRealm = new AppShiroRealm();
        appShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return appShiroRealm;
    }

    /*
     * @describe 自定義AppRealm
     * @param []
     * @return com.hongsui.win.home.controller.admin.web.realm.PcShiroRealm
    */
    @Bean
    public PcShiroRealm pcShiroRealm() {
        PcShiroRealm pcShiroRealm = new PcShiroRealm();
        pcShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return pcShiroRealm;
    }

    /*
     * @describe 自定義ThirdRealm
     * @param []
     * @return com.hongsui.win.home.controller.admin.web.realm.ThirdPathShiroRealm
    */
    @Bean
    public ThirdPathShiroRealm thirdPathShiroRealm() {
        ThirdPathShiroRealm thirdPathShiroRealm = new ThirdPathShiroRealm();
        thirdPathShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return thirdPathShiroRealm;
    }

配置會(huì)話管理器.

    @Bean
    public CustomerWebSessionManager sessionManager() {
        CustomerWebSessionManager sessionManager = new CustomerWebSessionManager();
        //會(huì)話驗(yàn)證器調(diào)度時(shí)間
        sessionManager.setSessionValidationInterval(1800000);
        //定時(shí)檢查失效的session
        sessionManager.setSessionValidationSchedulerEnabled(true);
        //是否在會(huì)話過(guò)期后會(huì)調(diào)用SessionDAO的delete方法刪除會(huì)話 默認(rèn)true
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionDAO(redisSessionDAO());
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        sessionManager.setSessionIdCookie(wapsession());
        sessionManager.setSessionIdCookieEnabled(true);
        return sessionManager;
    }

保證實(shí)現(xiàn)了Shiro內(nèi)部lifecycle函數(shù)的bean執(zhí)行.

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

開啟Shiro的注解(如@RequiresRoles,@RequiresPermissions等等),需借助SpringAOP掃描使用Shiro注解的類,并在必要時(shí)進(jìn)行安全邏輯驗(yàn)證,配置以下兩個(gè)bean(DefaultAdvisorAutoProxyCreatorAuthorizationAttributeSourceAdvisor)即可實(shí)現(xiàn)此功能.

    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
                new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(getDefaultWebSecurityManager());
        return authorizationAttributeSourceAdvisor;
    }

到此shiro框架已經(jīng)與springboot集成到項(xiàng)目中了,之后就可以編寫相應(yīng)的realm代碼以及在controller層實(shí)現(xiàn)登錄認(rèn)證了.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容