《跟我学shiro》的第28页到30页,写得是使用位操作算法实现权限匹配,但是在验验过程中初学者会做得不太顺利,原因是教材中的代码不全。为了通俗易懂,我把这个实验过程全部笔录一遍,并说明原理。
先来认识几个单词:
authorizer 【奥得ruai热】 [经] 核准人,授权人, 在shiro中它是授权API的入口。
permission 【拍米生】 允许;批准,正式认可,认可, 在shiro中,它就是最后要得到的权限。
resolver 【瑞肉喂】 下决心者,解决[答]问题者;溶媒;求解仪。
PermissionResolver 在shiro中,它是根据通配符解析成权限。
RolePermissionResolver 在shiro它是根据角色解析成权限。
第一步:新建一个shiro_6的maven工程;
第二步:修改成UTF-8编码;
第三步:写pom.xml,内容如下:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>0.2.23</version>
</dependency>
</dependencies>
第四步:写src/main/resource下写shiro的配置文件:shiro.ini,内容如下:
[main]
#授权入口
authorizer=org.apache.shiro.authz.ModularRealmAuthorizer
#采用解析Bit字符串得到权限
permissionResolver=www.jintingbo.com.BitAndWildPermissionResolver
authorizer.permissionResolver=$permissionResolver
#根据角色得到角色的权限
rolePermissionResolver=www.jintingbo.com.MyRolePermissionResolver
authorizer.rolePermissionResolver=$rolePermissionResolver
securityManager.authorizer=$authorizer
realm=www.jintingbo.com.MyRealm
securityManager.realms=$realm
第五步:写BitAndWildPermissionResolver类
看上面的配置,因为这个类不是shiro内部有的,所以要自己写。代码如下:
public class BitAndWildPermissionResolver implements PermissionResolver {
public Permission resolvePermission(String permissionString) {
if (permissionString.startsWith("+")) {
return new BitPermission(permissionString);
}
return new WildcardPermission(permissionString);
}
}
注意这个类中有一个BitPermission类也可自己写。代码如下:
public class BitPermission implements Permission {
private String resourceIdentify;
private int permissionBit;
private String instanceId;
public BitPermission(String permissionString) {
String[] array = permissionString.split("\\+");
if (array.length > 1) {
resourceIdentify = array[1];
}
if (StringUtils.isEmpty(resourceIdentify)) {
resourceIdentify = "*";
}
if (array.length > 2) {
permissionBit = Integer.valueOf(array[2]);
}
if (array.length > 3) {
instanceId = array[3];
}
if (StringUtils.isEmpty(instanceId)) {
instanceId = "*";
}
}
public boolean implies(Permission p) { //判断权限匹配
if (!(p instanceof BitPermission)) {
return false;
}
BitPermission other = (BitPermission) p;
if (!("*".equals(this.resourceIdentify) || this.resourceIdentify
.equals(other.resourceIdentify))) {
return false;
}
if (!(this.permissionBit == 0 || (this.permissionBit & other.permissionBit) != 0)) {
return false;
}
if (!("*".equals(this.instanceId) || this.instanceId
.equals(other.instanceId))) {
return false;
}
return true;
}
}
第六步:写MyRolePermissionResolver类
public class MyRolePermissionResolver implements RolePermissionResolver {
public Collection<Permission> resolvePermissionsInRole(String roleString) {
if("role1".equals(roleString)) {
return Arrays.asList((Permission)new WildcardPermission("menu:*"));
}
return null;
}
}
第七步:写MyRealm,这一部分,教材上的代码不全,所以在这里加上它的验证部分。
public class MyRealm extends org.apache.shiro.realm.AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addRole("role1");
authorizationInfo.addRole("role2");
authorizationInfo.addObjectPermission(new BitPermission("+user1+10"));
authorizationInfo.addObjectPermission(new WildcardPermission("user1:*"));
authorizationInfo.addStringPermission("+user2+10");
authorizationInfo.addStringPermission("user2:*");
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
String username = (String)token.getPrincipal(); //得到用户名
String password = new String((char[])token.getCredentials()); //得到密码
if(!"zhang".equals(username)) {
throw new UnknownAccountException(); //如果用户名错误
}
if(!"123".equals(password)) {
throw new IncorrectCredentialsException(); //如果密码错误
}
//如果身份认证验证成功,返回一个 AuthenticationInfo 实现;
return new SimpleAuthenticationInfo(username, password, getName());
}
public String getName() {
return "aaa";
}
public boolean supports(AuthenticationToken arg0) {
return arg0 instanceof UsernamePasswordToken;
}
}
第八步:写测试运行的类
public class MyTest {
private static void login(String configFile,String username,String password) {
//1、获取 SecurityManager 工厂,此处使用 Ini 配置文件初始化 SecurityManager
Factory<org.apache.shiro.mgt.SecurityManager> factory =
new IniSecurityManagerFactory(configFile);
//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(username,password);
subject.login(token);
}
public static void main(String[] args) {
login("classpath:shiro.ini","zhang","123");
Subject subject = SecurityUtils.getSubject();
try{
subject.isPermitted("system:menu111:view");
System.out.println("OK!");
}catch (UnauthorizedException e){
System.out.println("没有这个权限!");
}
}
}
第九步:运行
完毕
QQ:14280784