談談Shiro的原理及在SSM和SpringBoot兩種環(huán)境下的使用姿勢(上篇)


title: 談談Shiro的原理及在SSM和SpringBoot兩種環(huán)境下的使用姿勢(上篇)
categories:

  • Spring
    tags:
  • Shiro使用

本篇主要是記錄關于Shiro進行認證和授權的大致原理,然后是單獨在Shiro中實現(xiàn)認證和授權的方式。最后主要說明在傳統(tǒng)SSM的工程中使用Shiro和在SpringBoot的工程中使用Shiro進行整合科贬。關于認證和授權,我這里采用的是規(guī)范的RBAC權限模型,數(shù)據(jù)庫的建表語句已經(jīng)托管github的工程中泳梆。

在進行Shiro具體認證和授權的流程介紹之前,首先說一下Shiro中幾個比較重要的概念(其中的接口或者類)。

  1. Subject:含義為主體榜掌。Subject作為用戶端(使用Shiro進行授權的一端)的抽象,在Shiro中是通過一個接口來體現(xiàn)的优妙。在使用Shiro的時候,我們也就是通過調用Subject的認證和授權的方法來實現(xiàn)具體的認證和授權的。

  2. SecurityManager:含義為安全管理器憎账。SecurityManager是整個Shiro的核心所在,它負責對所有的Subject進行安全管理,我們在通過Subject進行授權和認證的時候,Subject其實是通過SecurityManager來實現(xiàn)具體業(yè)務邏輯的套硼。SecurityManager在Shiro中是通過一個接口來體現(xiàn)的,而且它繼承了Authenticator,Authorizer,SessionManager。如下圖:

    Aaron Swartz

    這樣SecurityManager的認證會交給Authenticator定義的業(yè)務邏輯完成,授權會交給Authorizer定義的業(yè)務邏輯完成,會話管理會交給SessionManager來完成胞皱。

  3. Authenticator:含義為認證器,主要是完成對用戶身份的認證邪意。Authenticator在Shiro是一個接口,在Shiro中提供了一個ModularRealmAuthenticator的實現(xiàn)類用于完成認證。ModularRealmAuthenticator已經(jīng)可以完成大多數(shù)的認證需求,如果我們有新的業(yè)務,那么我們通過自定義認證器來完成特殊的業(yè)務反砌。

  4. Authorizer:含義為授權器,主要是完成對用戶操作的授權雾鬼。Authorizer在Shiro中是一個接口,相比Authenticator,Shiro提供了更多的授權器的實現(xiàn)類,其中也包括類似的ModularRealmAuthorizer。這些默認的實現(xiàn)類可以完成大多數(shù)需求,如果我們有新的業(yè)務,那么我們通過自定義授權器來完成特殊的業(yè)務宴树。

  5. realm:含義為領域策菜。Realm在Shiro中也是一個接口,SecurityManager進行認證和授權的時候,它所需要的數(shù)據(jù)信息都是從Realm中獲取的。Realm有多種實現(xiàn)類,代表了Realm可以從多種數(shù)據(jù)源中讀取已經(jīng)配置的數(shù)據(jù)信息用于認證和授權。Realm在Shiro中是一個相當關鍵的部分,因為我們的授權器和認證器最終都是通過Realm來實現(xiàn)各自的業(yè)務的做入。

  6. SessionDAO:含義為Session會話.在Shiro中也是作為一個接口來體現(xiàn)的冒晰。sessiondao可以實現(xiàn)將session數(shù)據(jù)持久化。

  7. CacheManager:含義為緩存管理器竟块。用戶的認證和授權的信息可以緩存到CacheManager中,從而提升數(shù)據(jù)的訪問性能壶运。

  8. Cryptography:含義為密碼管理。shiro提供了Cryptography來作為我們信息的加密和界面的工具浪秘。

ok,在說完了Shiro中幾個比較關鍵的概念之后,我們開始看一下在Shiro中是如何進行的認證和授權的蒋情。

注:所有的sql都包含在了工程中

代碼地址: https://github.com/fuyunwang/ShiroDemo.git
認證:

下面這張圖說明了Shiro中進行認證的大致流程。

Aaron Swartz

可以看到,Shiro最終其實通過Realm來完成最終的認證耸携。我們上面也已經(jīng)提到,Realm其實作為一種數(shù)據(jù)源的地位存在,其包含多個實現(xiàn)類代表著從不同的數(shù)據(jù)源中進行數(shù)據(jù)信息的獲取棵癣。我這里通過使用其中一個實現(xiàn)類IniRealm來實現(xiàn)最簡單的認證流程。(具體代碼在v0.1tag下夺衍。)

    Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:inirealm-shiro.ini");
    
    SecurityManager securityManager = factory.getInstance();
    
    SecurityUtils.setSecurityManager(securityManager);
    
    Subject subject = SecurityUtils.getSubject();
    
    UsernamePasswordToken token=new UsernamePasswordToken("beautifulsoup", "password");
    
    try{
        subject.login(token);
    }catch(AuthenticationException e){
        e.printStackTrace();
    }

介紹完使用inirealm來完成從ini配置文件中獲取數(shù)據(jù)之后,我們做一個自定義Realm,來完成從數(shù)據(jù)庫這一數(shù)據(jù)源中獲取數(shù)據(jù)狈谊。
自定義Realm一般采用繼承自AuthorizingRealm的方式,然后重寫其中的認證和授權的方法,核心代碼如下,完整代碼在github。

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        String username=(String) token.getPrincipal();
        ShiroDemoMapper mapper=getShiroMapper();
        User user = mapper.findByUsername(username);
        if(null!=user){
            SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(username, user.getPassword(),TAG);
            return authenticationInfo;
        }
        return null;
    }

然后進行配置:

    [main]
    #進行自定義realm的配置
    customRealm=com.beautifulsoup.shiro.demo.realm.ShiroDemoRealm
    securityManager.realms=$customRealm

這樣我們自定義的realm就會生效了,我們可以實現(xiàn)從數(shù)據(jù)庫中獲取數(shù)據(jù),然后校驗我們主體subject的信息,從而實現(xiàn)判斷是否認證成功的功能沟沙。
這里我們認證的時候,在數(shù)據(jù)庫中采用明文存取的密碼,這當然是不合理的,所以通常情況下,我們會采用加鹽(salt)的方式,使用散列算法如MD5對我們原有的密碼進行加密然后存入數(shù)據(jù)庫中河劝。(改進之后的代碼在v0.2標簽下)

    首先修改配置文件,定義散列算法和散列次數(shù)等:
    [main]
    credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
    credentialsMatcher.hashAlgorithmName=md5
    credentialsMatcher.hashIterations=3
    #進行自定義realm的配置
    customRealm=com.beautifulsoup.shiro.demo.realm.ShiroDemoRealm
    customRealm.credentialsMatcher=$credentialsMatcher
    securityManager.realms=$customRealm
    然后修改realm
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        String username=(String) token.getPrincipal();
        ShiroDemoMapper mapper=getShiroMapper();
        User user = mapper.findByUsername(username);
        if(null!=user){
            SimpleAuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(username, user.getPassword(),
                    ByteSource.Util.bytes(user.getSalt()),TAG);
            return authenticationInfo;
        }
        return null;
    }

好,說完認證我們接下來說授權:

授權:

同樣,下面這張圖說明了在Shiro中進行授權的大致流程。

Aaron Swartz

可以看到,SecurityManager最終交給Realm進行授權,實際上Realm是會返回一個ModularRealmAuthorizer類,該類得到所有的系統(tǒng)配置的權限然后調用PermissionResolver進行了權限的匹配矛紫。

接上所講,我們還是使用ini的配置文件來配置shiro實現(xiàn)授權,主要是配置文件更加方便我們的管理赎瞎。

這里我們的權限信息定義在配置文件中,畢竟我們的權限信息大多數(shù)是固定的,而且對于權限不多的情況下,這種方式更簡單。對于授權的操作主要包括針對角色的授權和針對資源的授權兩種方式,由于基于角色的權限控制不如基于資源的權限控制更加靈活,所以我們采用基于資源的權限控制為例來介紹颊咬。

配置文件進行配置的方式如下(代碼在v0.3標簽):

        [users]
        #用戶beautifulsoup具有role1和role3的角色
        beautifulsoup=password,role1,role3
        [roles]
        #權限role1具有對01用戶訂單的創(chuàng)建權限和對02訂單資源的修改權限和對所有訂單的查詢操作务甥。
        role1=item:create:01,item:update:02,item:query
        role2=item:*:01,item:update:02
        role3=item:create:02,item:delete:02

基本權限的驗證:

        @Test
        public void testIniAuthorization(){
            Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:permission-shiro.ini");
            SecurityManager securityManager = factory.getInstance();
            SecurityUtils.setSecurityManager(securityManager);
            Subject subject = SecurityUtils.getSubject();
            //首先認證,認證通過之后才能授權
            UsernamePasswordToken token=new UsernamePasswordToken("beautifulsoup", "password");
            try{
                subject.login(token);
            }catch(AuthenticationException e){
                e.printStackTrace();
            }
            System.out.println("用戶的認證狀態(tài):"+subject.isAuthenticated());
            boolean isPermitted=subject.isPermittedAll("item:create:01","item:query");
            subject.checkPermissions("item:create:01","item:query");
            System.out.println(isPermitted);
        }

接下來使用自定義realm來實現(xiàn)用戶的授權。
在認證中已經(jīng)提到繼承自AuthorizingRealm,其提供了兩個方法,我們現(xiàn)在用第二個方法來實現(xiàn)授權的邏輯喳篇。(代碼在v0.4標簽)

        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(
                PrincipalCollection principals) {
            //得到認證成功之后憑證的身份信息
            String username=(String) principals.getPrimaryPrincipal();
            //查詢數(shù)據(jù)庫得到所有的權限列表
            List<String> permissionList=new ArrayList<String>();
            UserCustomMapper mapper=getUserCustomMapper();
            UserCustom userCustom = mapper.findUserCustomByUsername(username);
            Set<RoleCustom> roles=userCustom.getRoleSet();
            for(RoleCustom role:roles){
                Set<Permission> permissionSet = role.getPermissionSet();
                for (Permission permission:permissionSet) {
                    permissionList.add(permission.getPname());
                }
            }
            SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
            authorizationInfo.addStringPermissions(permissionList);
            return authorizationInfo;
        }       
        同樣我們也需要配置:
        [main]
        credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
        credentialsMatcher.hashAlgorithmName=md5
        credentialsMatcher.hashIterations=3
        #進行自定義realm的配置
        customRealm=com.beautifulsoup.shiro.demo.realm.ShiroDemoRealm
        customRealm.credentialsMatcher=$credentialsMatcher
        securityManager.realms=$customRealm

OK,到現(xiàn)在為止上篇已經(jīng)對Shiro所有認證和授權的基礎知識做過了介紹,下篇開始對SSM和SpringBoot中的Shiro的使用進行整合敞临。
代碼地址: https://github.com/fuyunwang/ShiroDemo.git

如果對您有過幫助,感謝您的一個star。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末麸澜,一起剝皮案震驚了整個濱河市挺尿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌痰憎,老刑警劉巖票髓,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異铣耘,居然都是意外死亡洽沟,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門蜗细,熙熙樓的掌柜王于貴愁眉苦臉地迎上來裆操,“玉大人怒详,你說我怎么就攤上這事∽偾” “怎么了昆烁?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長缎岗。 經(jīng)常有香客問我静尼,道長,這世上最難降的妖魔是什么传泊? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任鼠渺,我火速辦了婚禮,結果婚禮上眷细,老公的妹妹穿的比我還像新娘拦盹。我一直安慰自己,他們只是感情好溪椎,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布普舆。 她就那樣靜靜地躺著,像睡著了一般校读。 火紅的嫁衣襯著肌膚如雪沼侣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天地熄,我揣著相機與錄音华临,去河邊找鬼芯杀。 笑死端考,一個胖子當著我的面吹牛,可吹牛的內容都是我干的揭厚。 我是一名探鬼主播却特,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼筛圆!你這毒婦竟也來了裂明?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤太援,失蹤者是張志新(化名)和其女友劉穎闽晦,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體提岔,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡仙蛉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了碱蒙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荠瘪。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡夯巷,死狀恐怖,靈堂內的尸體忽然破棺而出哀墓,到底是詐尸還是另有隱情趁餐,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布篮绰,位于F島的核電站后雷,受9級特大地震影響,放射性物質發(fā)生泄漏吠各。R本人自食惡果不足惜喷面,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望走孽。 院中可真熱鬧惧辈,春花似錦、人聲如沸磕瓷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽困食。三九已至边翁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間硕盹,已是汗流浹背符匾。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瘩例,地道東北人啊胶。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像垛贤,于是被迫代替她去往敵國和親焰坪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內容

  • 文章轉載自:http://blog.csdn.net/w1196726224/article/details/53...
    wangzaiplus閱讀 3,399評論 0 3
  • 前言 Spring boot 是什么聘惦,網(wǎng)上的很多介紹某饰,這里博客就不多介紹了。如果不明白Spring boot是什么...
    xuezhijian閱讀 17,911評論 13 39
  • 一 shiro 是什么 shiro 是一個功能強大和易于使用的Java安全框架善绎,為開發(fā)人員提供一個直觀而全面的解決...
    司鑫閱讀 58,249評論 17 98
  • 構建一個互聯(lián)網(wǎng)應用黔漂,權限校驗管理是很重要的安全措施,這其中主要包含: 認證 - 用戶身份識別禀酱,即登錄 授權 - 訪...
    zhuke閱讀 3,509評論 0 30
  • 一:基礎概念 什么是權限管理 權限管理包括用戶身份認證和授權兩部分炬守,簡稱認證授權。對于需要訪問控制的資源用戶首先經(jīng)...
    QGUOFENG閱讀 559評論 0 0