2021SC@SDUSC
一.Demo代码
这是在shiro源码的quickstart目录下有QuickStart.java文件,截取了其中鉴权部分的代码。
// 测试一个角色:
// 判断当前用户的角色是否为schwartz
if (currentUser.hasRole("schwartz")) { // 1
log.info("May the Schwartz be with you!");
} else {
log.info("Hello, mere mortal.");
}
// 测试类型化权限(而不是实例级)
// 判断当前用户是否被允许使用lightsaber执行wield动作
if (currentUser.isPermitted("lightsaber:wield")) { // 2
log.info("You may use a lightsaber ring. Use it wisely.");
} else {
log.info("Sorry, lightsaber rings are for schwartz masters only.");
}
// 实例级权限:
// 判断当前用户是否被允许驾驶牌照为eagle5的winnebago
if (currentUser.isPermitted("winnebago:drive:eagle5")) {
log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " +
"Here are the keys - have fun!");
} else {
log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
}
二.源码分析
本文针对鉴权中的isPermitted()方法进行分析
2
public class DelegatingSubject implements Subject {
// 如果允许此Subject执行操作或访问由指定权限字符串汇总的资源,则返回true。
// 这是对应类型安全的Permission变量的重载方法。
public boolean isPermitted(String permission) {
// hasPrincipals()方法已经在上一篇文章中分析过
return hasPrincipals() && securityManager.isPermitted(getPrincipals(), permission);
}
}
public class ModularRealmAuthorizer implements Authorizer, PermissionResolverAware, RolePermissionResolverAware {
public boolean isPermitted(PrincipalCollection principals, String permission) {
// 确保Realm是配置好的
assertRealmsConfigured();
for (Realm realm : getRealms()) {
if (!(realm instanceof Authorizer)) continue;
if (((Authorizer) realm).isPermitted(principals, permission)) {
return true;
}
}
return false;
}
}
public abstract class AuthorizingSecurityManager extends AuthenticatingSecurityManager {
public boolean isPermitted(PrincipalCollection principals, String permissionString) {
return this.authorizer.isPermitted(principals, permissionString);
}
}
public abstract class AuthorizingRealm extends AuthenticatingRealm
implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware {
public boolean isPermitted(PrincipalCollection principals, String permission) {
// 获取权限解析器,利用权限解析器的resolvePermission()方法解析字符串形式的权限
// 2.1 -> getPermissionResolver()
// 2.2 -> resolvePermission()
Permission p = getPermissionResolver().resolvePermission(permission);
return isPermitted(principals, p); // 2.3
}
}
2.1
PermissionResolver解析字符串值并将其转换为Permission实例。
默认的WildcardPermissionResolver应该适用于大多数目的,它构造了WildcardPermission对象。
但是,如果应用程序希望使用不同的Permission实现,可以配置任何解析器。
PermissionResolver被许多Shiro组件使用,比如注释、属性文件配置、URL配置等。
当指定了权限的String表示形式,并且在执行安全检查之前需要将String转换为permission实例时,此方法非常有用。
Shiro默认在几乎所有组件中都支持通配符权限,我们以WildcardPermissionResolver的形式来实现。
WildcardPermissions默认支持的一个优点是,它使得在数据库中存储复杂的权限变得非常容易——也使得在JSP文件、注释等中表示权限变得非常容易,在这些文件中,简单的字符串表示非常有用。
虽然这恰好是Shiro的默认值,但你当然可以通过向Shiro组件提供该接口的任何实例来提供自定义的String-to-Permission转换。
public abstract class AuthorizingRealm extends AuthenticatingRealm
implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware {
public PermissionResolver getPermissionResolver() {
return permissionResolver;
}
}
2.2
WildcardPermission是一个非常灵活的权限构造,支持多级权限匹配。但一般会遵循下面解释的一些标准约定。
在最简单的形式中,WildcardPermission可以用作简单的权限字符串。可以授予用户一个“editNewsletter”权限,然后通过调用检查用户是否拥有editNewsletter权限。
subject.isPermitted("editNewsletter")
这整体相当于:
subject.isPermitted( new WildcardPermission("editNewsletter") )
简单的权限字符串可能适用于简单的应用程序,但它要求你拥有“viewNewsletter”,“deleteNewsletter”,“createNewsletter”等权限。您还可以使用通配符为用户授予“*”权限(赋予该类名称),这意味着它们拥有所有权限。但是使用这种方法,就不能说一个用户拥有“所有通讯权限”。出于这个原因,WildcardPermission支持多级权限。
public interface PermissionResolver {
// 根据给定的字符串表示形式解析Permission。
Permission resolvePermission(String permissionString);
}
// PermissionResolver实现,它根据输入字符串返回一个新的通配符权限。
public class WildcardPermissionResolver implements PermissionResolver {
// 返回基于指定的permissionString构造的新的WildcardPermission实例。
public Permission resolvePermission(String permissionString) {
return new WildcardPermission(permissionString, caseSensitive);
}
}
2.3
本方法和上一篇文章中掉用的方法是一致的。
public abstract class AuthorizingRealm extends AuthenticatingRealm
implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware {
public boolean isPermitted(PrincipalCollection principals, Permission permission) {
AuthorizationInfo info = getAuthorizationInfo(principals);
return isPermitted(permission, info);
}
}
(完)