shiro 瞅完就會用(ssm+shiro)

一 shiro 是什么

shiro 是一個功能強大和易于使用的Java安全框架脯爪,為開發(fā)人員提供一個直觀而全面的解決方案的認(rèn)證则北,授權(quán),加密痕慢,會話管理。

二 shiro 能干什么


先上圖:


所有功能

shiro 四個主要的功能

  • Authentication:身份認(rèn)證/登錄掖举,驗證用戶是不是擁有相應(yīng)的身份快骗;
  • Authorization:授權(quán),即權(quán)限驗證塔次,判斷某個已經(jīng)認(rèn)證過的用戶是否擁有某些權(quán)限訪問某些資源方篮,一般授權(quán)會有角色授權(quán)和權(quán)限授權(quán);
  • SessionManager:會話管理励负,即用戶登錄后就是一次會話藕溅,在沒有退出之前,它的所有信息都在會話中继榆;會話可以是普通JavaSE環(huán)境的巾表,也可以是如Web環(huán)境的,web 環(huán)境中作用是和 HttpSession 是一樣的略吨;
  • Cryptography:加密集币,保護數(shù)據(jù)的安全性,如密碼加密存儲到數(shù)據(jù)庫晋南,而不是明文存儲惠猿;

shiro 的其它幾個特點

  • Web Support:Web支持,可以非常容易的集成到Web環(huán)境负间;
  • Caching:緩存偶妖,比如用戶登錄后,其用戶信息政溃、擁有的角色/權(quán)限不必每次去查趾访,這樣可以提高效率;
  • Concurrency:shiro支持多線程應(yīng)用的并發(fā)驗證董虱,即如在一個線程中開啟另一個線程扼鞋,能把權(quán)限自動傳播過去;
  • Testing:提供測試支持愤诱;
  • Run As:允許一個用戶假裝為另一個用戶(如果他們允許)的身份進行訪問云头;
  • Remember Me:記住我,這個是非常常見的功能淫半,即一次登錄后溃槐,下次再來的話不用登錄了。
三 shiro 架構(gòu)

先上圖


架構(gòu)

從圖中我們可以看到不管是任何請求都會經(jīng)過 SecurityManager 攔截并進行相應(yīng)的處理科吭,shiro 幾乎所有的功能都是由 SecurityManager 來管理昏滴。
其中:

  • Subject:主體猴鲫,相當(dāng)與是請求過來的"用戶"
  • SecurityManager: 是 Shiro 的心臟;所有具體的交互都通過 SecurityManager 進行攔截并控制谣殊;它管理著所有 Subject拂共、且負責(zé)進行認(rèn)證和授權(quán)、及會話姻几、緩存的管理
  • Authenticator:認(rèn)證器宜狐,負責(zé)主體認(rèn)證的,即確定用戶是否登錄成功鲜棠,我們可以使用  Shiro 提供的方法來認(rèn)證肌厨,有可以自定義去實現(xiàn),自己判斷什么時候算是用戶登錄成功
  • Authrizer:授權(quán)器豁陆,即權(quán)限授權(quán),給 Subject 分配權(quán)限吵护,以此很好的控制用戶可訪問的資源
  • Realm:一般我們都需要去實現(xiàn)自己的 Realm 盒音,可以有1個或多個 Realm,即當(dāng)我們進行登錄認(rèn)證時所獲取的安全數(shù)據(jù)來源(帳號/密碼)
  • SessionManager:為了可以在不同的環(huán)境下使用 session 功能馅而,shiro 實現(xiàn)了自己的 sessionManager 祥诽,可以用在非 web 環(huán)境下和分布式環(huán)境下使用
  • SessionDAO:對 session 的 CURD 操作
  • CacheManager:緩存控制器,來管理如用戶瓮恭、角色雄坪、權(quán)限等的緩存的;
  • Cryptography:密碼模塊屯蹦,Shiro提高了一些常見的加密組件用于如密碼加密/解密的维哈。
四 shiro 的主要功能 - 身份認(rèn)證

1 Subject 認(rèn)證

身份認(rèn)證就是在應(yīng)用中誰能證明他就是他本人,一般會使用用戶名和密碼作為認(rèn)證信息。

2 Subject 認(rèn)證主體

Subject 認(rèn)證主體包含兩個信息:

  • Principals:身份,即用戶名
  • Credentials:憑證,即密碼

** 3 認(rèn)證流程**

認(rèn)證流程
  1. 用戶發(fā)送請求進行 Subject 認(rèn)證(調(diào)用 subject.login(token))
  2. SecurityManager 會去 Authenticator(認(rèn)證器)中查找相應(yīng)的 Realms(可能不止一個)源
  3. Realms 可以根據(jù)不同類型的 Realm 中去查找用戶信息,并進行判斷是否認(rèn)證成功

4 快速搭建 helloWorld

  1. 導(dǎo)包
<dependencies>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency>
    </dependencies>
  1. 創(chuàng)建 Realm /resources/shiro.ini
[users]
acey=123456
jack=111
  1. 進行身份驗證
public class HelloWorld {

    public static void main(String[] args) {
//        加載配置文件,初始化 SecurityManager 工廠
        Factory<SecurityManager> factory = new IniSecurityManagerFactory
          ("classpath:shiro.shiro.ini");
//        獲取 SecurityManager 實例
        SecurityManager securityManager = factory.getInstance();
//        把 SecurityManager 綁定到 SecurityUtils 中
        SecurityUtils.setSecurityManager(securityManager);
//        得到當(dāng)前執(zhí)行的用戶
        Subject currentUser = SecurityUtils.getSubject();
//        創(chuàng)建 token 令牌,用戶名/密碼
        UsernamePasswordToken token = new UsernamePasswordToken("acey", "123456");
        try {
//            身份驗證
            currentUser.login(token);
            System.out.println("登錄成功");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("登錄失敗");
        }
    }
}

四 shiro 的主要功能 - 授權(quán)

權(quán)限授權(quán)就是訪問控制,在應(yīng)用中控制誰能訪問哪些資源

1 權(quán)限認(rèn)證中的幾個元素

  • 權(quán)限:即操作某個資源的權(quán)限登澜,這些資源可以是某個鏈接阔挠,也可以是某個圖片,也可以是對某個模塊的數(shù)據(jù)的 CURL
  • 角色:即權(quán)限的集合脑蠕,一個角色可以有多個權(quán)限
  • 用戶:代表訪問的用戶购撼,即  Subject

2 授權(quán)的流程

授權(quán)流程
  1. 當(dāng)用戶訪問應(yīng)用中的某個資源時,會被 SecurityManager 攔截.
  2. SecurityManager 會去調(diào)用 Authorizer(授權(quán)器)
  3. Authorizer 會根據(jù) Subject 的身份去相應(yīng)的 Realm 中去查找該 Subject 是否有權(quán)限去訪問該資源

3 授權(quán)實現(xiàn)

  1. 導(dǎo)包
  2. 配置 permission(權(quán)限) resources/shiro_permission.ini
[main] 
authc.loginUrl=/login  //表示用戶登錄失敗跳轉(zhuǎn)到 /login
roles.unauthorrizedUrl=/unauthorrized.jsp //表示用戶沒有對應(yīng)的訪問角色跳轉(zhuǎn)到/unauthorrized.jsp
perms.unauthorrizedUrl=/unauthorrized.jsp  //表示用戶沒有對應(yīng)的訪問權(quán)限跳轉(zhuǎn)到/unauthorrized.jsp

[users]
acey=123456,role1,role2
jack=123,role1
[roles]
role1=user:select // role1 角色有訪問 user:select 的權(quán)限
role2=user:add,/delete //role2 角色有訪問 user:add 和 /delete 的權(quán)限

[urls]
/login=anon  //表示任何用戶都可以訪問 /login
/index=authc //表示只有身份認(rèn)證通過的用戶才可以訪問 /index
/index=roles[role1,role2...] //表示只有用戶含有 role1 role2 ... 角色才可以訪問 /index
/index=perms["user:create","/update"]  //表示只有用戶含有 "user:create" 
                      和"/update"權(quán)限才可以訪問 /index 
/index?=authc //`?`通配符,表示一個字符,如/index1 /indexa /index- (不能匹配/index) ,
                      將符合這種規(guī)則的請求進行`authc`攔截
/index*=authc  `*`通配符,表示零個或一個或多個字符,如/index1213asd /index /index2 ,
                      將符合這種規(guī)則的請求進行`authc`攔截
/index/**=authc  `**`表示匹配零個或一個或多個路徑,如/index/create /index/create/update/...  ,
                      將符合這種規(guī)則的請求進行`authc`攔截
/index*/**authc  可以匹配 /index12/create/update/...

3)配置 roles (角色) resources/shiro_role.ini

[users]
acey=123456,role1,role2 //表示有一個用戶,用戶名是acey,密碼為123456,有role1和role2角色
jack=123,role1
  1. 驗證用戶角色是否足夠
public class RoleTest {

//  使用 checkRole 來檢驗角色時,若權(quán)限不足會返回 false
    @Test
    public void testHasRole() {
        Subject currentUser= ShiroUtil.login("classpath:shiro_role.ini", "acey", "123456");
        // Subject currentUser=ShiroUtil.login("classpath:shiro_role.ini", "jack", "123");
        System.out.println(currentUser.hasRole("role1")?"has role1":"has not role1");
        currentUser.logout();
    }

    //  使用 checkRole 來檢驗角色時,若權(quán)限不足會拋出異常
    @Test
    public void testCheckRole() {
        Subject currentUser=ShiroUtil.login("classpath:shiro_role.ini", "acey", "123456");
        // Subject currentUser=ShiroUtil.login("classpath:shiro_role.ini", "jack", "123");
        currentUser.checkRole("role1");

        currentUser.logout();
    }
}
  1. 驗證用戶權(quán)限是否足夠
public class PermissionTest {

//  使用 checkPermission 來檢驗權(quán)限時,若權(quán)限不足會返回 false
    @Test
    public void testIsPermitted() {
        Subject currentUser= ShiroUtil.login("classpath:shiro_permission.ini", "acey", "123456");
        System.out.println(currentUser.isPermitted("user:select")?"has user:select":"hsa not user:select");

        currentUser.logout();
    }

//  使用 checkPermission 來檢驗權(quán)限時,若權(quán)限不足會拋出異常
    @Test
    public void testCheckPermitted() {
        Subject currentUser=ShiroUtil.login("classpath:shiro_permission.ini", "acey", "123456");
        // Subject currentUser=ShiroUtil.login("classpath:shiro_permission.ini", "jack", "123");
        currentUser.checkPermission("user:select");
        currentUser.logout();
    }
}
五 ssm 和 shiro 整合

  1. 導(dǎo)入依賴
    2)配置 web.xml(shiro過濾器)
 <!-- shiro過濾器定義 -->
    <filter>  
        <filter-name>shiroFilter</filter-name>  
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
    <init-param>  
    <!-- 該值缺省為false,表示生命周期由SpringApplicationContext管理,設(shè)置為true則表示由ServletContainer管理 -->  
    <param-name>targetFilterLifecycle</param-name>  
    <param-value>true</param-value>  
    </init-param>  
    </filter>  
    <filter-mapping>  
            <filter-name>shiroFilter</filter-name>  
            <url-pattern>/*</url-pattern>  
    </filter-mapping>
    
    

3)編寫自己的 Realm(一般權(quán)限都是從數(shù)據(jù)庫中查找,所以需要自定義)

public class MyRealm extends AuthorizingRealm{

    @Resource
    private UserService userService;
    
    /**
     * 為當(dāng)前登錄的用戶授予角色和權(quán)限
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //獲取用戶名
        String userName=(String)principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
        //進行授權(quán)角色
        authorizationInfo.setRoles(userService.getRoles(userName));
        //進行授權(quán)權(quán)限
        authorizationInfo.setStringPermissions(userService.getPermissions(userName));
        return authorizationInfo;
    }

    /**
     *驗證當(dāng)前登錄的用戶
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName=(String)token.getPrincipal();
        //根據(jù)用戶名查找用戶信息
            User user=userService.getByUserName(userName);
            if(user!=null){
                AuthenticationInfo authcInfo=new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(),getName());
                return authcInfo;
            }else{
                return null;                
            }
    }
}
  1. spring 和 shiro 配置整合
...
<!-- 自定義Realm -->
    <bean id="myRealm" class="com.acey.realm.MyRealm"/>
    
    <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
      <property name="realm" ref="myRealm"/>  
    </bean>  
    
    <!-- Shiro過濾器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
        <!-- Shiro的核心安全接口,這個屬性是必須的 -->  
        <property name="securityManager" ref="securityManager"/>
        <!-- 身份認(rèn)證失敗谴仙,則跳轉(zhuǎn)到登錄頁面的配置 -->  
        <property name="loginUrl" value="/index.jsp"/>
        <!-- 權(quán)限認(rèn)證失敗迂求,則跳轉(zhuǎn)到指定頁面 -->  
        <property name="unauthorizedUrl" value="/unauthor.jsp"/>  
        <!-- Shiro連接約束配置,即過濾鏈的定義 -->  
        <property name="filterChainDefinitions">  
            <value>  
                 /login=anon
                /admin*=authc
                /student=roles[teacher]
                /teacher=perms["user:create"]
            </value>  
        </property>
    </bean>  
    
    <!-- 保證實現(xiàn)了Shiro內(nèi)部lifecycle函數(shù)的bean執(zhí)行 -->  
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>  
    
    <!-- 開啟Shiro注解 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>  
        <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">  
      <property name="securityManager" ref="securityManager"/>  
    </bean>  
...

一般角色和權(quán)限都存在數(shù)據(jù)庫中,所以我們還可以自定義一個 filter 去自己驗證每一個請求的 Subject 是否有權(quán)限去訪問,這樣我們就可以減少對過濾鏈的維護.比如

<!-- Shiro過濾器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
        <!-- Shiro的核心安全接口,這個屬性是必須的 -->  
        <property name="securityManager" ref="securityManager"/>
        <!-- 身份認(rèn)證失敗,則跳轉(zhuǎn)到登錄頁面的配置 -->  
        <property name="loginUrl" value="/index.jsp"/>
        <!-- 權(quán)限認(rèn)證失敗晃跺,則跳轉(zhuǎn)到指定頁面 -->  
        <property name="unauthorizedUrl" value="/unauthor.jsp"/>  
        <!-- Shiro連接約束配置,即過濾鏈的定義 -->  
        <property name="filterChainDefinitions">  
            <value>  
                 /login=anon
                /admin*=authc
                /student=roles[teacher]
                /teacher=perms["user:create"]
            </value>  
        </property>
    </bean>  

可以改成

<!-- Shiro過濾器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
        <!-- Shiro的核心安全接口,這個屬性是必須的 -->  
        <property name="securityManager" ref="securityManager"/>
        <!-- 身份認(rèn)證失敗揩局,則跳轉(zhuǎn)到登錄頁面的配置 -->  
        <property name="loginUrl" value="/index.jsp"/>
        <!-- 權(quán)限認(rèn)證失敗,則跳轉(zhuǎn)到指定頁面 -->  
        <property name="unauthorizedUrl" value="/unauthor.jsp"/>  
        <property name="ownFilter" class="ownFilter.class">
        <!-- Shiro連接約束配置,即過濾鏈的定義 -->  
        <property name="filterChainDefinitions">  
            <value>  
                 /login=anon
               /**=ownFilter
            </value>  
        </property>
    </bean>  

待續(xù)! 歡迎大家拍磚

源碼地址:ShirDemos

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哼审,一起剝皮案震驚了整個濱河市谐腰,隨后出現(xiàn)的幾起案子孕豹,更是在濱河造成了極大的恐慌,老刑警劉巖十气,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件励背,死亡現(xiàn)場離奇詭異,居然都是意外死亡砸西,警方通過查閱死者的電腦和手機叶眉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芹枷,“玉大人衅疙,你說我怎么就攤上這事≡Т龋” “怎么了饱溢?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長走芋。 經(jīng)常有香客問我绩郎,道長,這世上最難降的妖魔是什么翁逞? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任肋杖,我火速辦了婚禮,結(jié)果婚禮上挖函,老公的妹妹穿的比我還像新娘状植。我一直安慰自己,他們只是感情好怨喘,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布津畸。 她就那樣靜靜地躺著,像睡著了一般哲思。 火紅的嫁衣襯著肌膚如雪洼畅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天棚赔,我揣著相機與錄音帝簇,去河邊找鬼。 笑死靠益,一個胖子當(dāng)著我的面吹牛丧肴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胧后,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼芋浮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了壳快?” 一聲冷哼從身側(cè)響起纸巷,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤镇草,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后瘤旨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梯啤,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年存哲,在試婚紗的時候發(fā)現(xiàn)自己被綠了因宇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡祟偷,死狀恐怖察滑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情修肠,我是刑警寧澤贺辰,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站嵌施,受9級特大地震影響魂爪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜艰管,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蒋川。 院中可真熱鬧牲芋,春花似錦、人聲如沸捺球。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽氮兵。三九已至裂逐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泣栈,已是汗流浹背卜高。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留南片,地道東北人掺涛。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像疼进,于是被迫代替她去往敵國和親薪缆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前言 Spring boot 是什么伞广,網(wǎng)上的很多介紹拣帽,這里博客就不多介紹了疼电。如果不明白Spring boot是什么...
    xuezhijian閱讀 17,911評論 13 39
  • 構(gòu)建一個互聯(lián)網(wǎng)應(yīng)用,權(quán)限校驗管理是很重要的安全措施减拭,這其中主要包含: 認(rèn)證 - 用戶身份識別蔽豺,即登錄 授權(quán) - 訪...
    zhuke閱讀 3,510評論 0 30
  • 一:基礎(chǔ)概念 什么是權(quán)限管理 權(quán)限管理包括用戶身份認(rèn)證和授權(quán)兩部分,簡稱認(rèn)證授權(quán)峡谊。對于需要訪問控制的資源用戶首先經(jīng)...
    QGUOFENG閱讀 559評論 0 0
  • Shiro(代碼) 1.1 簡介 Apache Shiro是Java的一個安全框架茫虽。目前,使用Apache Shi...
    ZZS_簡閱讀 489評論 0 0
  • 1.簡介 Apache Shiro是Java的一個安全框架既们。功能強大濒析,使用簡單的Java安全框架,它為開發(fā)人員提供...
    H_Man閱讀 3,171評論 4 48