1. 程式人生 > >JavaWeb日記——Shiro之角色和許可權

JavaWeb日記——Shiro之角色和許可權

上一篇博客中講到了Shiro的登入功能,這篇講講Shiro的角色和許可權

在Shiro中,一個使用者可以有多種角色,一種角色可以有多種許可權
在執行某些行為前時,我們既可以判斷是否是該角色也可以判斷是否擁有該許可權

下面展示一個簡單的例子

POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation
="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.jk.shiroLearning</groupId> <artifactId>chapter2</artifactId> <version>1.0-SNAPSHOT</version> <properties> <version-slf4j
>
1.6.6</version-slf4j> </properties> <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${version-slf4j}</version> </dependency>
<dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${version-slf4j}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- slf4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.7</version> </dependency> <!--slf4j-log4j12 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> <!--shiro核心包--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.2</version> </dependency> </dependencies> </project>

同之前一樣

Shiro.ini

[users]
#帳號=密碼,角色1,角色2……
jack=123456,role1,role2

[roles]
#對資源user擁有createupdate許可權,*代表任意,可在物件:行為:例項中替換
role1=user:create,user:update:*
#對資源user1例項擁有delete許可權
role2=user:delete:1

驗證角色和許可權

public class RoleAndPermissionTest {

    @Test
    public void main(){
        //1、獲取SecurityManager工廠,此處使用Ini配置檔案初始化SecurityManager
        Factory<SecurityManager> factory =
                new IniSecurityManagerFactory("classpath:shiro.ini");

        //2、得到SecurityManager例項 並繫結給SecurityUtils
        org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);

        //3、得到Subject及建立使用者名稱/密碼身份驗證Token(即使用者身份/憑證)
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("jack", "123456");

        try {
            //4、登入,即身份驗證
            subject.login(token);
            //判斷是否有角色,沒有則會丟擲異常
            subject.checkRole("role1");
            //判斷是否有許可權,沒有則會丟擲異常
            subject.checkPermission("user:update:1");
            //判斷是否有角色
            System.out.println(subject.hasRole("role1"));
            System.out.println(subject.hasRole("role2"));
            System.out.println(subject.hasRole("role3"));
            //判斷有許可權
            System.out.println(subject.isPermitted("user:update:1"));
            System.out.println(subject.isPermitted("user:delete:2"));
        } catch (AuthenticationException e) {
            //5、身份驗證失敗
            e.printStackTrace();
        }
        System.out.println(subject.isAuthenticated());
        //6、退出
        subject.logout();
    }
}

如果不想把使用者資訊,角色寫死在配置檔案裡怎麼辦?這時就需要一個繼承自AuthorizingRealm的類來實現認證的授權

自定義Realm

public class MyRealm extends AuthorizingRealm {

    //授權,呼叫checkRole/checkPermission/hasRole/isPermitted都會執行該方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //可通過不同principal賦予不同許可權
        if (principals.getPrimaryPrincipal().equals("jack")){
            //授予角色role1和role2
            authorizationInfo.addRole("role1");
            authorizationInfo.addRole("role2");
            //授予對user任何行為任何例項的許可權
            authorizationInfo.addObjectPermission(new WildcardPermission("user:*"));
            //等同於
            //authorizationInfo.addStringPermission("user:*");
        }
        return authorizationInfo;
    }

    //認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String)token.getPrincipal();  //得到使用者名稱
        String password = new String((char[])token.getCredentials()); //得到密碼
        if(!"jack".equals(username)) {
            throw new UnknownAccountException(); //如果使用者名稱錯誤
        }
        if(!"123456".equals(password)) {
            throw new IncorrectCredentialsException(); //如果密碼錯誤
        }
        //如果身份認證驗證成功,返回一個AuthenticationInfo實現;
        return new SimpleAuthenticationInfo(username, password, getName());
    }
}

shiro-realm.ini

[main]
#自定義authorizer
authorizer=org.apache.shiro.authz.ModularRealmAuthorizer
securityManager.authorizer=$authorizer

#自定義realm 一定要放在securityManager.authorizer賦值之後(因為呼叫setRealms會將realms設定給authorizer,並給各個Realm設定permissionResolver和rolePermissionResolver)
realm=com.jk.realm.MyRealm
securityManager.realms=$realm

驗證角色和許可權

public class RealmTest {
    @Test
    public void main(){
        //1、獲取SecurityManager工廠,此處使用Ini配置檔案初始化SecurityManager
        Factory<SecurityManager> factory =
                new IniSecurityManagerFactory("classpath:shiro-realm.ini");

        //2、得到SecurityManager例項 並繫結給SecurityUtils
        org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);

        //3、得到Subject及建立使用者名稱/密碼身份驗證Token(即使用者身份/憑證)
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("jack", "123456");

        try {
            //4、登入,即身份驗證
            subject.login(token);
            //判斷是否有角色,沒有則會丟擲異常
            subject.checkRole("role1");
            //判斷是否有許可權,沒有則會丟擲異常
            subject.checkPermission("user:update:1");
            //判斷是否有角色
            System.out.println(subject.hasRole("role1"));
            System.out.println(subject.hasRole("role2"));
            System.out.println(subject.hasRole("role3"));
            //判斷有許可權
            System.out.println(subject.isPermitted("user:update:1"));
            System.out.println(subject.isPermitted("user:delete:2"));
        } catch (AuthenticationException e) {
            //5、身份驗證失敗
            e.printStackTrace();
        }
        System.out.println(subject.isAuthenticated());
        //6、退出
        subject.logout();
    }

}