Authorization, also called access control, is to control who can access which resources in the application (such as accessing pages/editing data/page operations, etc.).
First, let's understand a few key objects:
Subject, Role, Permission, Resource
main body
That is, the user who accesses the application, which is represented by Subject in Shiro.
Role
Represents a set of operations, which can be understood as a set of permissions. Generally, we will give users roles instead of permissions, that is, users can have a set of permissions, which is more convenient when granting permissions.
Typical examples are: project manager, technical director, CTO, development engineer, etc. are roles, and different roles have a different set of permissions.
permission
The atomic authorization unit in the security policy, through permissions, we can indicate whether the user has the right to operate a certain resource in the application. That is, permissions indicate whether the user can access a certain resource in the application
resource
Anything a user can access in an application, such as accessing a JSP page, viewing/editing some data, accessing a business method, printing text, etc., is a resource. Users can only access after authorization.
Authorization method
Shiro supports three ways of authorization:
Programmatically: done by writing an if/else authorization block:
Subject subject = SecurityUtils.getSubject(); if (subject.hasRole("admin")) { // has permission } else { // does n't have permission }
Annotated: done by placing the corresponding annotation on the executed Java method:
@RequiresRoles( " admin " ) public void hello() { // Have permission }
No permission will throw the corresponding exception;
JSP/GSP tags: Completed by corresponding tags on JSP/GSP pages:
<shiro:hasRole name="admin"> <!—authorized—> </shiro:hasRole>
String wildcard permissions
Rule: "Resource Identifier: Operation: Object Instance ID" That is, what operation can be performed on which instance of which resource.
It supports wildcard permission strings by default, ":" indicates the division of resources/operations/instances; "," indicates the division of operations; "*" indicates any resource/operation/instance.
例如:subject().checkPermissions("user:update,delete");
1. External realization
Implement AuthorizingRealm
public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String)principals.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setRoles(userService.findRoles(username)); authorizationInfo.setStringPermissions(userService.findPermissions(username)); System.out.println(userService.findPermissions(username)); return authorizationInfo; } protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String)token.getPrincipal(); User user = userService.findByUsername(username); if(user == null) { throw new UnknownAccountException();//没找到帐号 } if(Boolean.TRUE.equals(user.getLocked())) { throw new LockedAccountException(); //帐号锁定 } return new SimpleAuthenticationInfo( user.getUsername(), //用户名 user.getPassword(), //密码 ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt getName() //realm name ); } }
The process is as follows:
1. First call the Subject.isPermitted*/hasRole* interface, which will be delegated to the SecurityManager, and then the SecurityManager will be delegated to the Authorizer;
2. Authorizer is the real authorizer. If we call isPermitted("user:view"), it will first convert the string into the corresponding Permission instance through PermissionResolver;
3. Before authorization, it will call the corresponding Realm to obtain the corresponding role/permission of the Subject to match the incoming role/permission;
4. The Authorizer will judge whether the role/authority of the Realm matches the incoming one. If there are multiple Realms, it will be delegated to ModularRealmAuthorizer for circular judgment. If it matches, such as isPermitted*/hasRole*, it will return true, otherwise it will return false to indicate that the authorization failed.
ModularRealmAuthorizer performs multiple Realm matching process:
1. First check whether the corresponding Realm implements the Authorizer;
2. If Authorizer is implemented, then call its corresponding isPermitted*/hasRole* interface to match;
3. If there is a Realm match, it will return true, otherwise it will return false.
If Realm is authorized, it should inherit AuthorizingRealm, and its process is:
1. If you call hasRole*, you can directly get AuthorizationInfo.getRoles() and compare it with the incoming role;
2. First of all, if you call isPermitted("user:view"), first convert the permission string into the corresponding Permission instance through PermissionResolver. By default, WildcardPermissionResolver is used, that is, WildcardPermission converted to wildcard;
3. Obtain the Permission instance collection through AuthorizationInfo.getObjectPermissions(); obtain the string collection through AuthorizationInfo.getStringPermissions() and resolve it into a Permission instance through PermissionResolver; then obtain the user's role and resolve the permission collection corresponding to the role through RolePermissionResolver (not implemented by default) , you can provide yourself);
4. Then call Permission. implies(Permission p) to compare with the incoming permissions one by one, and return true if there is a match, otherwise false.
Excerpted from : Chapter 3 Authorization - "Learn Shiro With Me"