shiro 瞅完就會(huì)用(ssm+shiro)

一 shiro 是什么

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

二 shiro 能干什么


先上圖:


所有功能

shiro 四個(gè)主要的功能

  • Authentication:身份認(rèn)證/登錄,驗(yàn)證用戶是不是擁有相應(yīng)的身份;
  • Authorization:授權(quán),即權(quán)限驗(yàn)證,判斷某個(gè)已經(jīng)認(rèn)證過的用戶是否擁有某些權(quán)限訪問某些資源,一般授權(quán)會(huì)有角色授權(quán)和權(quán)限授權(quán);
  • SessionManager:會(huì)話管理,即用戶登錄后就是一次會(huì)話,在沒有退出之前,它的所有信息都在會(huì)話中;會(huì)話可以是普通JavaSE環(huán)境的,也可以是如Web環(huán)境的,web 環(huán)境中作用是和 HttpSession 是一樣的;
  • Cryptography:加密,保護(hù)數(shù)據(jù)的安全性,如密碼加密存儲(chǔ)到數(shù)據(jù)庫,而不是明文存儲(chǔ);

shiro 的其它幾個(gè)特點(diǎn)

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

先上圖


架構(gòu)

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

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

1 Subject 認(rèn)證

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

2 Subject 認(rèn)證主體

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

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

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

認(rèn)證流程
  1. 用戶發(fā)送請(qǐng)求進(jìn)行 Subject 認(rèn)證(調(diào)用 subject.login(token))
  2. SecurityManager 會(huì)去 Authenticator(認(rèn)證器)中查找相應(yīng)的 Realms(可能不止一個(gè))源
  3. Realms 可以根據(jù)不同類型的 Realm 中去查找用戶信息,并進(jìn)行判斷是否認(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. 進(jìn)行身份驗(yàn)證
public class HelloWorld {

    public static void main(String[] args) {
//        加載配置文件,初始化 SecurityManager 工廠
        Factory<SecurityManager> factory = new IniSecurityManagerFactory
          ("classpath:shiro.shiro.ini");
//        獲取 SecurityManager 實(shí)例
        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 {
//            身份驗(yàn)證
            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)證中的幾個(gè)元素

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

2 授權(quán)的流程

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

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

  1. 導(dǎo)包
  2. 配置 permission(權(quán)限) resources/shiro_permission.ini
[main] 
authc.loginUrl=/login  //表示用戶登錄失敗跳轉(zhuǎn)到 /login
roles.unauthorrizedUrl=/unauthorrized.jsp //表示用戶沒有對(duì)應(yīng)的訪問角色跳轉(zhuǎn)到/unauthorrized.jsp
perms.unauthorrizedUrl=/unauthorrized.jsp  //表示用戶沒有對(duì)應(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 //`?`通配符,表示一個(gè)字符,如/index1 /indexa /index- (不能匹配/index) ,
                      將符合這種規(guī)則的請(qǐng)求進(jìn)行`authc`攔截
/index*=authc  `*`通配符,表示零個(gè)或一個(gè)或多個(gè)字符,如/index1213asd /index /index2 ,
                      將符合這種規(guī)則的請(qǐng)求進(jìn)行`authc`攔截
/index/**=authc  `**`表示匹配零個(gè)或一個(gè)或多個(gè)路徑,如/index/create /index/create/update/...  ,
                      將符合這種規(guī)則的請(qǐng)求進(jìn)行`authc`攔截
/index*/**authc  可以匹配 /index12/create/update/...

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

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

//  使用 checkRole 來檢驗(yàn)角色時(shí),若權(quán)限不足會(huì)返回 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 來檢驗(yàn)角色時(shí),若權(quán)限不足會(huì)拋出異常
    @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. 驗(yàn)證用戶權(quán)限是否足夠
public class PermissionTest {

//  使用 checkPermission 來檢驗(yàn)權(quán)限時(shí),若權(quán)限不足會(huì)返回 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 來檢驗(yàn)權(quán)限時(shí),若權(quán)限不足會(huì)拋出異常
    @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();
        //進(jìn)行授權(quán)角色
        authorizationInfo.setRoles(userService.getRoles(userName));
        //進(jìn)行授權(quán)權(quán)限
        authorizationInfo.setStringPermissions(userService.getPermissions(userName));
        return authorizationInfo;
    }

    /**
     *驗(yàn)證當(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的核心安全接口,這個(gè)屬性是必須的 -->  
        <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>  
    
    <!-- 保證實(shí)現(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ù)庫中,所以我們還可以自定義一個(gè) filter 去自己驗(yàn)證每一個(gè)請(qǐng)求的 Subject 是否有權(quán)限去訪問,這樣我們就可以減少對(duì)過濾鏈的維護(hù).比如

<!-- Shiro過濾器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
        <!-- Shiro的核心安全接口,這個(gè)屬性是必須的 -->  
        <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的核心安全接口,這個(gè)屬性是必須的 -->  
        <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)容合作請(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 前言 Spring boot 是什么,網(wǎng)上的很多介紹,這里博客就不多介紹了。如果不明白Spring boot是什么...
    xuezhijian閱讀 18,028評(píng)論 13 39
  • 構(gòu)建一個(gè)互聯(lián)網(wǎng)應(yīng)用,權(quán)限校驗(yàn)管理是很重要的安全措施,這其中主要包含: 認(rèn)證 - 用戶身份識(shí)別,即登錄 授權(quán) - 訪...
    zhuke閱讀 3,631評(píng)論 0 30
  • 一:基礎(chǔ)概念 什么是權(quán)限管理 權(quán)限管理包括用戶身份認(rèn)證和授權(quán)兩部分,簡稱認(rèn)證授權(quán)。對(duì)于需要訪問控制的資源用戶首先經(jīng)...
    QGUOFENG閱讀 612評(píng)論 0 0
  • Shiro(代碼) 1.1 簡介 Apache Shiro是Java的一個(gè)安全框架。目前,使用Apache Shi...
    ZZS_簡閱讀 529評(píng)論 0 0
  • 1.簡介 Apache Shiro是Java的一個(gè)安全框架。功能強(qiáng)大,使用簡單的Java安全框架,它為開發(fā)人員提供...
    H_Man閱讀 3,257評(píng)論 4 47

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