This is the 12th day of my participation in the More text Challenge. For details, see more text Challenge

The business scenario

First, there are two ways to control permissions: RBAC and ACL

RBAC is role-based control, whereas ACL permissions are directly related to users

Flask’s original intention in my understanding is to be fast, precise and ruthless, so we give up the complicated ACL and use RBAC for permission management

According to the RBAC concept, a brief description of the system’s authority construction:

  1. The four concepts of interface/permission/role/user are used for control and corresponding tables are created
  2. Create a relationship table between interfaces and permissions, permissions and roles, and so on
  3. The user queries the interface information when logging in
  4. Verification is performed when accessing the interface

There are plenty of examples of the first three steps on the web, and the code is pretty simple (except for the tree)

This article focuses on step four, which uses Python’s decorators to implement interface validation

plan

Problem of ideas

When designing permission validation, the first response is to match against the requested URL

For example, if the interface is/API /user, the user is matched in the interface information. If the interface does not exist, the user does not have the corresponding permission

But for the endpoint format interface, there is a problem. What about/API /user/1?

Many people can certainly think of regular rules, but this requires custom rules for different interfaces, and different resource ids can even affect the design of the interface, which is not applicable

So the right thing to do is to use the code, identify the code for the interface and verify it

Writing decorators

With the solution in mind, we started writing the code

The first step is to install flask_jWT_extended

Step 2: Write a decorator with an interface code:

from functools import wraps

from flask_jwt_extended import verify_jwt_in_request, get_jwt

from flask_koala.core.exceptions import BusinessException


def authorization(code: str = None) :
    """ Authentication decorator """

    def decorator(fn) :
        @wraps(fn)
        def wrapper(*args, **kwargs) :
            try:
                verify_jwt_in_request()
            except Exception:
                raise BusinessException("No access".403)
            if code is None:
                return fn(*args, **kwargs)
            authorities = get_jwt()['authorities']
            if code not in authorities:
                raise BusinessException("No access".403)
            return fn(*args, **kwargs)

        return wrapper

    return decorator
Copy the code

Here I use a global custom exception, replace BusinessException with what you need

As a final step, just annotate the interface:

@auth.route('/info')
class Info(Resource) :
    @authorization(code='api:auth:info')
    def get(self) :
        """ "Get user information :return: user information entity """ "
        return RestResult.success(get_jwt_identity())
Copy the code