Shiro入門

八月加油!

shiro權限管理:
        shiro架構:

          

            securityManager:安全管理器,主體(subject)進行認證和授權。
            authenticator:認證器,主體認證所需要的。
            anthorizer:授權器,主體授權所需要的。
            sessionManager:shiro提供了一套session的管理模式。常規的session都是web容器進行統一管理。
            sessionDao:通過sessionDao來管理個性化session數據。
            cacheManager:緩存管理器,session數據和授權數據進行緩存。 -- 和ehcache整合進行緩存數據管理。
            realm:域,相當於數據源。通過realm存取認證/授權的相關數據。 -- realm中含有認證和授權邏輯。
            cryptography:加密/解密組件管理。

用戶認證流程:

             
            1. 通過ini配置文件創建SecurityManager
            2. 調用subject.login方法進行主體提交認證
            3. SecurityManager最終是通過ModularRealmAuthenticator進行認證
            4. ModularRealmAuthenticator調用IniRealm去ini配置文件中查詢用戶信息
            5. IniRealm根據輸入的token(UsernamePasswordToken)從ini中查詢用戶信息,根據賬號查詢用戶信息
                如果查詢到用戶信息,就給ModularRealmAuthenticator返回用戶信息(賬號和密碼)
                如果查詢不到,就給ModularRealmAuthenticator返回null
            6. ModularRealmAuthenticator接收IniRealm返回Authentication認證信息
               如果返回的認證信息是null,ModularRealmAuthenticator拋出異常(org.apache.shiro.authc.UnknownAccountException)
              如果返回的認證信息不是null(說明inirealm找到了用戶),對IniRealm返回用戶密碼(在ini文件中存在)和token中的密碼進行對比, 如果不一致拋出異常(org.apache.shiro.authc.IncorrectCredentialsException)

用戶認證Demo:

        1.ini文件構建:採用ini文件可以實現數據分組,存儲方式上和properties一致,都是採用鍵值對方式。

   shiro-simple.ini文件:

#用戶信息分組
[users]
zhangsan=123


        2.工程搭建,採用Junit測試,書寫測試用例。

//用戶登錄和退出認證
    @Test
    public void testLoginAndLogout(){

        //1. 通過ini文件構建SecurityManager
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-simple.ini");

        //2. 創建SecurityManager
        SecurityManager securityManager = factory.getInstance();

        //3. 將SecurityManager設置到當前的環境中
        SecurityUtils.setSecurityManager(securityManager);

        //4. 從SecurityManager中創建一個subject
        Subject subject = SecurityUtils.getSubject();

        //5. 在認證提交前準備token -- 令牌
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123");

        try {
            //6. 執行認證提交
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }

        //7. 是否認證通過
        System.out.println("shiro--登錄是否認證通過:" + subject.isAuthenticated());

        //8. 退出操作
        subject.logout();

    }

       3.測試結果:

       認證成功:

       認證失敗:

      用戶名未通過認證,返回Null,報org.apache.shiro.authc.UnknownAccountException異常

      密碼未通過驗證,報org.apache.shiro.authc.IncorrectCredentialsException異常

 

用戶授權流程:

        

        1.對subject進行授權,調用方法isPermitted("permission串")。
        2.SecurityManager執行授權,通過ModularRealmAuthorizer執行授權。
     3.ModularRealmAuthorizer執行realm(自定義的CustomRealm)從數據庫查詢權限數據。調用realm的授權方法:doGetAuthorizationInfo。
        4.realm從數據庫查詢權限數據,返回ModularRealmAuthorizer。
        5.ModularRealmAuthorizer調用PermissionResolver進行權限串比對。
       6.如果比對後,isPermitted中"permission串"在realm查詢到權限數據中,說明用戶訪問permission串有權限,否則 沒有權限,拋出異常。

用戶授權Demo:

        1.ini文件構建:採用ini文件可以實現數據分組,存儲方式上和properties一致,都是採用鍵值對方式。

        shiro-permission.ini文件:

# 用戶
[users]
# 用戶zhangsan的密碼是132,此用戶具有role1和role2兩個角色
zhangsan=123,role1,role2

# 權限
[roles]
# 角色role1對資源user具有create、update權限
role1=user:create,user:update
# 角色role2對資源user具有create、delete權限
role2=user:create,user:delete


        2.工程搭建,採用Junit測試,書寫測試用例。

 //角色授權,資源授權測試
    @Test
    public void testAuthorization(){

        //1. 通過ini文件構建SecurityManager
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-permission.ini");

        //2. 創建SecurityManager
        SecurityManager securityManager = factory.getInstance();

        //3. 將SecurityManager設置到當前的環境中
        SecurityUtils.setSecurityManager(securityManager);

        //4. 從SecurityManager中創建一個subject
        Subject subject = SecurityUtils.getSubject();

        //5. 在認證提交前準備token -- 令牌
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123");

        try {
            //6. 執行認證提交
            subject.login(token);
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }

        //7. 是否認證通過
        System.out.println("shiro--登錄是否認證通過:" + subject.isAuthenticated());

        //基於角色的授權
        //hasRole傳入單個角色標識
        boolean isHasRole = subject.hasRole("role1");
        //hasRole傳入多個角色標識
        boolean isHasRoles = subject.hasAllRoles(Arrays.asList("role1", "role2"));
        System.out.println("單個角色判斷:" + isHasRole + "\n" + "多個角色判斷:" + isHasRoles);

        //使用check方法進行授權,授權不通過會拋出異常
//        subject.checkRole("role3");

        //基於資源的授權
        //isPermitted傳入單個權限標識符
        boolean isPermitted = subject.isPermitted("user:create:1");
        //isPermitted傳入多個權限標識符
        boolean isPermittedAll = subject.isPermittedAll("user:create", "user:delete");
        System.out.println("單個權限判斷:" + isPermitted + "\n" + "多個權限判斷:" + isPermittedAll);

        //使用check方法進行授權,授權不通過會拋出異常
//        subject.checkPermission("items:add");
    }

        3.測試結果:

        授權成功:

        授權失敗:

自定義Realm:

       基於框架的權限管理實質上就是對數據庫進行的安全管理,權限管理的操作對象均是通過Realm進行的,針對不同的需求和場景,可以自定義Realm進行權限管理。即通過Realm從數據庫中獲取權限數據

  CustomRealm 類:

/*
* 自定義realm -- 模擬數據庫操作
* */
public class CustomRealm extends AuthorizingRealm {


    //複寫命名方法
    @Override
    public void setName(String name) {
        super.setName("CustomRealm");
    }

    //用於認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        // 從token中取出身份信息
        String userCode = (String) authenticationToken.getPrincipal();

        // 根據用戶輸入的userCode從數據庫中查詢密碼 -- 這裏模擬數據庫查詢結果
        String passWord = "123";

        //查詢不到返回Null

        //查詢到返回認證信息AuthenticationInfo
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userCode, passWord, this.getName());
        return simpleAuthenticationInfo;
    }

    //用於授權
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        //從principle中獲取主體身份信息
        String userCode  = (String) principalCollection.getPrimaryPrincipal();

        //根據身份信息,獲取權限信息 -- 模擬數據庫連接
        List<String> permissions = new ArrayList<String>();
        permissions.add("user:create"); //用戶創建權限
        permissions.add("items:add");   //商品添加權限

        //查詢到權限數據,返回授權信息
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        //將授權信息添加到SimpleAuthorizationInfo中
        simpleAuthorizationInfo.addStringPermissions(permissions);
        return simpleAuthorizationInfo;
    }
}

ini配置文件:

[main]
# 自定義realm
customRealm= com.shiro.realm.CustomRealm
# 將realm設置到SecurityManager,類比spring中的注入
securityManager.realms=$customRealm

通過自定義的Reaml可以對數據庫進行權限數據獲取,返回認證信息AuthenticationInfo、授權信息SimpleAuthorizationInfo。

接着就是認證/授權了,測試用例只需要在ini文件加載處進行更改。測試用例的本質就是模擬用戶的操作。

//1. 通過ini文件構建SecurityManager
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章