JavaWeb日記——Shiro之角色和許可權
阿新 • • 發佈:2019-01-24
上一篇博客中講到了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擁有create、update許可權,*代表任意,可在物件:行為:例項中替換
role1=user:create,user:update:*
#對資源user的1例項擁有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();
}
}