authorization

Authorization, or access control, controls who can access what resources. After identity authentication, the principal needs to assign permissions to access system resources. Some resources without permissions cannot be accessed.

Key objects for authorization

Authorization can be simply understood as Who doing How to What/Which.

  • Who: a Subject needs to access resources in the system.
  • What/Which: Resources, such as system menus, pages, buttons, class methods, system product information, etc. Resources include resource types and resource instances. For example, commodity information is resource type, Type01 is resource instance, and commodity information numbered 001 is resource instance.
  • How: Permission, which specifies a principal’s Permission to operate on a resource. Permissions are meaningless without resources, such as user query permission, user add permission, call permission of a certain class method, and modification permission of user 001. Permissions are used to know the operation permissions of the subject on resources.

Authorization process

Authorization must be performed only after authentication is successful.

Authorization Mode (RBAC)

RBAC contains two main authorization modes:

  • Role-based Access Control: Implements role-centered Access Control.

    Pseudocode can be expressed as:

    if (subject.hasRole("admin")) {
        // Perform the operation
    }
    Copy the code
  • Resource-based Access Control: Implements resource-centered Access Control.

    Pseudocode can be expressed as:

    if (subject.isPermitted("user:find:*")) {
        // Perform the operation
    }
    Copy the code

    The isPermission pass-in parameter is a permission string of the format “Resource type: Operation: resource instance”.

    “User: find: *” indicates that the Subject has query permission (action type) for all user instances.

    “User: * : 001” indicates that the Subject has all permissions (operation instances) on the user instance whose ID is 001.

Shiro permission string

1. Composition rules

Permission strings used in Shiro must follow the rules specified by Shiro.

The permission string combination rule is as follows: “Resource type Identifier: Operation: Resource instance Identifier”

  • Resource type identifier: Generally, resources are divided into modules. For example, the user module, product module, order module, etc., the corresponding resource type identifier is: user, product, order.

  • Operation: Generally add, delete, update, find (create, delete, update, find), as well as the * flag.

  • Resource instance identifiers: If Subject controls the resource type, the resource instance identifier is “*”; If the Subject controls a resource instance, then the resource instance identifier needs to be the unique identifier (ID, etc.) for that resource.

Example 2.

“* : * : *” indicates that the Subject has all operation permissions on all instances of all types, which is equivalent to a super administrator.

“User: create: *” indicates that Subject has the permission to create all instances of the user type. It can be abbreviated as “user: create”.

“User: update: 001” indicates that Subject has the permission to modify the user instance whose ID is 001.

“User: * : 001” indicates that Subject has all permissions on the user instance whose ID is 001.

Shiro authorization method

Shiro provides three implementations of background authorization:

  • programmatic
  • Annotation type
  • Tabbed (deprecated, can only be used in template engines such as JSP, Thymeleaf)

1. The programmatic

Subject subject = SecurityUtils.getSubject();
if (subject.hasRole("admin")) {
    / / have permission
} else {
    / / without permission
}
Copy the code

2. The annotation type

@RequiresRoles("admin")
public void find(a) {
    / / have permission
}
Copy the code

Shiro authorized source code

The SimpleAccountRealm class is the low-level authentication and authorization operations that Shiro does by default, with the doGetAuthenticationInfo method handling authentication and the doGetAuthorizationInfo method handling authorization.

public class SimpleAccountRealm extends AuthorizingRealm {...// Authentication processing
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        SimpleAccount account = getUser(upToken.getUsername());

        if(account ! =null) {

            if (account.isLocked()) {
                throw new LockedAccountException("Account [" + account + "] is locked.");
            }
            if (account.isCredentialsExpired()) {
                String msg = "The credentials for account [" + account + "] are expired";
                throw newExpiredCredentialsException(msg); }}return account;
    }

    // Authorization processing
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = getUsername(principals);
        USERS_LOCK.readLock().lock();
        try {
            return this.users.get(username);
        } finally{ USERS_LOCK.readLock().unlock(); }}}Copy the code

Shiro authorization Demo

Authorization must be based on authentication. Therefore, Demo uses the MD5 encryption authentication described in the previous section to implement authorization.

1. Role-based access control

Add a role to Subject in the authorization action in defining a Realm

public class UserMD5Realm extends AuthorizingRealm {

    // Authorize the operation
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // Get identity information (username)
        String username = (String) principals.getPrimaryPrincipal();

        // Load the user's role information from the database into SimpleAuthorizationInfo based on the identity information
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRole("admin");
        simpleAuthorizationInfo.addRole("user");

        // Returns the permission information object
        return simpleAuthorizationInfo;
    }

    // The authentication operation
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {...return null; }}Copy the code

Authorization process

public static void main(String[] args) {
	
    // The authentication operation.// If the authentication succeeds, authorization can be performed
    if (subject.isAuthenticated()) {

        // Verify that Subject has the admin role
        if (subject.hasRole("admin")) {
            // Specific authorization operation
        }

        // Verify that the Subject has both the admin and user roles
        if (subject.hasAllRoles(Arrays.asList("admin"."user"))) {
            // Specific authorization operation
        }

        Verify that the Subject has one or more of the following roles
        boolean[] hasRoles = subject.hasRoles(Arrays.asList("admin"."user"));
        for (boolean hasRole : hasRoles) {
            if (hasRole) {
                // Specific authorization operation}}}}Copy the code

2. Access control based on permission

Add authorization information to Subject in the authorization action in Defining a Realm

public class UserMD5Realm extends AuthorizingRealm {

    // Authorize the operation
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // Get identity information (username)
        String username = (String) principals.getPrimaryPrincipal();

        // Load the user's permission information from the database into SimpleAuthorizationInfo based on the identity information
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
		simpleAuthorizationInfo.addStringPermission("user:create:001");
        simpleAuthorizationInfo.addStringPermission("user:update:*");

        // Returns the permission information object
        return simpleAuthorizationInfo;
    }

    // The authentication operation
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {...return null; }}Copy the code

Authorization process

public static void main(String[] args) {
   	
    // The authentication operation.// If the authentication succeeds, authorization can be performed
    if (subject.isAuthenticated()) {
        
        // Determine whether the Subject has permission to create all user instances
        if (subject.isPermitted("user:create:*")) {
            // Specific authorization operation
        }

        // Determine that the Subject has the permission to create all user instances and to modify user instance 001
        if (subject.isPermittedAll("user:create:*"."user:update:001")) {
            // Specific authorization operation
        }

        // Determine whether the Subject has one or more of the following permissions
        boolean[] permissions = subject.isPermitted("user:create:*"."user:update:001");
        for (boolean permission : permissions) {
            if (permission) {
                // Specific authorization operation}}}}Copy the code