Java環境下shiro的測試-認證與受權

Java環境下shiro的測試

1.導入依賴的核心jar包

<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-core</artifactId>
  <version>1.3.2</version>
</dependency>

2.認證程序

2.1 構建users配置文件 xxx.ini doGetAuthenticationInfo方法從該配置文件中獲取數據與token中比對

[users]
test=123456
lisi=123456

測試程序

public class TestShiro {
    public static void main(String[] args) {
        //獲取安全管理器工廠
        IniSecurityManagerFactory iniSecurityManagerFactory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //獲取安全管理器
        SecurityManager securityManager = iniSecurityManagerFactory.getInstance();
        //set認證器
        SecurityUtils.setSecurityManager(securityManager);
        //subject發起認證,獲取subject
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken authenticationToken = new UsernamePasswordToken("test","123456");

        //認證失敗會拋出異常  密碼:CredentialsException   帳戶:UnknownAccountException
        try {
            subject.login(authenticationToken);
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }

        //當前subject是否定證經過
        boolean authenticated = subject.isAuthenticated();
        System.out.println(authenticated);
    }
}

認證流程:

token攜帶身份和憑證信息--->subject發起認證--->SimpleAccountRealm(doGetAuthenticationInfo)獲取配置文件中的用戶信息---->CredentialsMatcher接口的實現類SimpleCredentialsMatcher:doCredentialsMatch方法對配置文件中的信息與token攜帶的信息進行比對--->認證成功或者失敗。java

3.Shiro框架中的關鍵對象:

AuthenticatingRealm  //抽象類
    //3.關鍵屬性 該屬性爲憑證匹配器
    CredentialsMatcher credentialsMatcher;
    //1.該方法爲抽象方法 其做用使用來獲取數據
    protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken var1) throws AuthenticationException;
SimpleAccountRealm
//2.實現了AuthenticatingRealm抽象方法,用來獲取配置文件中的用戶信息,該類不作數據比對
SimpleCredentialsMatcher
//4.shiro中默認的憑證匹配器
  public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        Object tokenCredentials = this.getCredentials(token);
        Object accountCredentials = this.getCredentials(info);
        return this.equals(tokenCredentials, accountCredentials);
    }

必需要知道的類與接口,否則很難理解自定義Realm時屬性爲何設置,使用哪一種實現類方法等等:

如下代碼或者截圖貼出最重要的地方.sql

類繼承關係
數據庫

AuthenticatingRealm類apache

abstract class AuthenticatingRealm{
    //憑證匹配器 接口,其實現類作數據比對
    private CredentialsMatcher credentialsMatcher;
    //獲取配置文件中的用戶信息
    protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken var1) throws AuthenticationException;
}

該抽象方法返回類型AuthenticationInfo接口:api

AuthorizingRealm類 抽象方法後面測試受權時使用安全

abstract class AuthorizingRealm{
    //
    //該抽象方法  獲取數據  獲取受權的數據   
    protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection var1);
}

該抽象方法返回類型AuthorizationInfo接口:
app

CredentialsMatcher憑證匹配器接口:框架

其中:SimpleCredentialsMatcher是shiro中默認的憑證匹配器,其子類Hashxxx等都是作加密認證時使用
ide

4.開發自定義Realm

public class MyRealm extends AuthenticatingRealm {
    //實現抽象方法doGetAuthenticationInfo
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        String principal =(String) authenticationToken.getPrincipal();
        //查庫取回User對象
        SqlSession sqlSession = null;
        try {
            sqlSession = MySqlSession.getSqlSession();
        } catch (IOException e) {
            e.printStackTrace();
        }
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserByUserName(principal);
        AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(principal,user.getPassword(),this.getName());
        return authenticationInfo;
    }
}

4.1通知shiro使用自定義realm

[main]
#自定義 realm
customRealm=com.nyist.test.MyRealm
#將realm設置到securityManager
securityManager.realms=$customRealm

注意:須要導入一個jar測試

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

5.shiro的加密認證方式

5.1.使用shiro提供的Md5Hash類爲一個字符串加密進行測試

public class TestMD5 {
    public static void main(String[] args) {
        Md5Hash hash = new Md5Hash("123456","salt",1024);
        String s = hash.toHex();
        System.out.println(s);
        //a18d2133f593d7b0e3ed488560404083
    }
}

5.2.修改配置文件,加入憑證匹配器的相關配置

[main]
#自定義憑證匹配器
hashedCredentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#憑證匹配器通知AuthenticatingRealm,因爲自定義realm繼承了AuthenticatingRealm,直接設置已有的MyRealm屬性便可

#自定義 realm
customRealm=com.nyist.test.MyRealm
customRealm.credentialsMatcher=$hashedCredentialsMatcher
hashedCredentialsMatcher.hashAlgorithmName=MD5
hashedCredentialsMatcher.hashIterations=1024

#將realm設置到securityManager .realms使用set方式賦值
securityManager.realms=$customRealm

坑:Caused by: java.lang.IllegalStateException: Required 'hashAlgorithmName' property has not been set. This is required to execute the hashing algorithm.

HashedCredentialsMatcher類中set方法很是規,set方法爲:setHashAlgorithmName

爲何這麼設置憑證匹配器?

自定義MyRealm extends AuthorizingRealm,實現兩個抽象方法

AuthenticationInfo doGetAuthenticationInfo()來自於AuthenticatingRealm類,獲取認證數據

AuthorizationInfo doGetAuthorizationInfo()來自於AuthorizingRealm類,獲取受權數據

public class MyRealm extends AuthorizingRealm {

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        String principal =(String) authenticationToken.getPrincipal();
        //userDao.queryUserByUserName
        SqlSession sqlSession = null;
        try {
            sqlSession = MySqlSession.getSqlSession();
        } catch (IOException e) {
            e.printStackTrace();
        }
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserByUserName(principal);

        /*
        * ByteSource.Util.bytes("salt") 鹽字段來自數據庫,憑證匹配器不能寫死鹽值
        * 安全管理器能夠獲取到AuthenticationInfo中的鹽值 對用戶界面的憑證加密
        * */
        AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(principal,user.getPassword(),ByteSource.Util.bytes("salt"),this.getName());
        return authenticationInfo;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //獲取身份信息 Principal用戶名、手機號、郵箱地址等 一個主體能夠有多個身份,可是必須有一個主身份(Primary Principal)
        String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
        /*
        * 用戶----角色----權限
        *   中間表   中間表
        * */
        //由primaryPrincipal查庫--->得到角色info ---->獲取權限info
        SqlSession sqlSession = null;
        try {
            sqlSession = MySqlSession.getSqlSession();
        } catch (IOException e) {
            e.printStackTrace();
        }
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserByUserName(primaryPrincipal);
        //測試基於角色的受權
        /*if (primaryPrincipal.equals(user.getUsername())){
            // class SimpleAuthorizationInfo implements AuthorizationInfo
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            authorizationInfo.addRole("super");
            return authorizationInfo;
        }*/
        //測試基於資源的受權
        if(primaryPrincipal.equals(user.getUsername())){
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            authorizationInfo.addStringPermission("user:delete");
            authorizationInfo.addStringPermissions(Arrays.asList("admin:delete","admin:add"));
            return authorizationInfo;
        }
        return null;
    }
}

一張圖看懂認證受權關係:

受權的api

  • 基於角色

    //判斷當前主體是否包含此角色
                boolean b = subject.hasRole("super");
                List<String> list = Arrays.asList("super", "admin");
                //判斷當前主體是否包含某個角色
                boolean[] booleans = subject.hasRoles(list);
                //判斷當前主體是否包含所有的角色
                boolean b = subject.hasAllRoles(list);
  • 基於資源

    boolean b = subject.isPermitted("admin:delete");
                String[] strs={"admin:delete", "admin:add"};
                boolean[] permitted = subject.isPermitted(strs);
                boolean permittedAll = subject.isPermittedAll(strs);

資源權限的標識符

權限字符串的規則是:「資源標識符:操做:資源實例標識符」,意思是對哪一個資源的哪一個實例具備什麼操做,「:」是資源/操做/實例的分割符,權限字符串也可使用*通配符。

例子:

  • 用戶建立權限:user:create,或user:create:*
  • 用戶修改實例001的權限:user:update:001
  • 用戶實例001的全部權限:user:*:001
相關文章
相關標籤/搜索