Shiro permission verification
1. Test class
first call
subject().isPermitted("user1:update");
subject will delegate to SecurityManager
The SecurityManager will then delegate to the Authorizer;
Authorizer is the real authorizer
Authorizer is an interface, and will then call the isPermitted method of its implementation class (ModularRealmAuthorizer) for authentication
It can be seen that as long as there is a permission verification pass, it will return true
public boolean isPermitted(PrincipalCollection principals, String permission) { assertRealmsConfigured(); for (Realm realm : getRealms()) { if (!(realm instanceof Authorizer)) continue; if (((Authorizer) realm).isPermitted(principals, permission)) { return true; } } return false; }in
The source code of the assertRealmsConfigured method is: its main function is to determine whether the realm is empty (this method is pretty good, learn it)
protected void assertRealmsConfigured() throws IllegalStateException { Collection<Realm> realms = getRealms(); if (realms == null || realms.isEmpty()) { String msg = "Configuration error: No realms have been configured! One or more realms must be " + "present to execute an authorization operation."; throw new IllegalStateException(msg); } }
At this point, which isPermitted(principals, permission) method above calls the method isPermitted(principals, permission) of its implementation interface (Authorizer)
And then call the method of its implementation class (AuthorizingRealm)
First, parse the incoming permissions to be verified.
Use developer specified resolver BitAndWildPermissionResolver
public boolean isPermitted(PrincipalCollection principals, String permission) { Permission p = getPermissionResolver().resolvePermission(permission); return isPermitted (principals, p); }
Use a custom permission parser to convert string permissions to permissions of type Permission
public class BitAndWildPermissionResolver implements PermissionResolver { public Permission resolvePermission(String permissionString) { / / Start with the + sign to go to the custom permission parser if(permissionString.startsWith("+")){ return new BitPermission(permissionString); } //The rest go shiro, the default wildcard permission parser return new WildcardPermission(permissionString); } }
Then compare the incoming permissions :
public boolean isPermitted(PrincipalCollection principals, Permission permission) { AuthorizationInfo info = getAuthorizationInfo(principals); return isPermitted (permission, info); }This method works:
(0) First get the permission information from the cache, if not, go to realm to get it
Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
(1) First obtain the permission set from the custom MyRealm class (original, unparsed, including string, wild, bit various types of initial permission parameters)
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { 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; }
Note: Questions about caching
if (info == null) {
// Call template method if the info was not found in a cache
info = doGetAuthorizationInfo(principals);
// If the info is not null and the cache has been created, then cache the authorization info.
if (info != null && cache != null) {
if (log.isTraceEnabled()) {
log.trace("Caching authorization info for principals: [" + principals + "].");
}
Object key = getAuthorizationCacheKey(principals);
cache.put(key, info);
}
}
Here is the default cache implementation. If you configure the cache in shiro, the current permission information will be cached in the cache.
(2) Actual comparison of permissions (parsing permission strings)
return isPermitted (permission, info);The critical moment has come:
protected boolean isPermitted(Permission permission, AuthorizationInfo info) { Collection<Permission> perms = getPermissions(info); if (perms != null && !perms.isEmpty()) { for (Permission perm : perms) { if (perm.implies(permission)) { return true; } } } return false; }
Among them, the place with blue characters on a yellow background will convert the permission information (good and bad) just obtained from the custom realm into a unified Permission object for comparison
The final parsed permissions are as follows (including directly granted permissions, and permissions owned by those who have roles)
Preparations complete ( permissions to be verified, which the user actually has )
Can start comparing posessPermissions
Collection<Permission> possessPermissions= getPermissions(info);
if (possessPermissions!= null && !possessPermissions.isEmpty()) {
for (Permission perm : possessPermissions) {
if (perm.implies(wantTocheckPermissions)) {
return true;
}
}
}
return false;
true if one returns true