node-casbin / sequelize-adapter

Sequelize adapter for Casbin
https://github.com/casbin/node-casbin
Apache License 2.0
64 stars 34 forks source link

Leveraging connection pool instead of creating connection every time in adapter for each REST API #30

Closed puneetjindal closed 4 years ago

puneetjindal commented 4 years ago

Hi, I have just started integrating casbin into my saas multi tenant app for authorization management. I am building REST APIs which can be used by app's frontend roles and permission management module.

For this I have create multiple apis:-

  1. role listing at system and tenant level
  2. user listing for a given role for a tenant
  3. create custom role at tenant level

....

a glimpse of how i am using node sequelize adapter as below

async function returnEnforcer () {
  const a = await SequelizeAdapter.newAdapter({
    username: process.env.DB_USER,
    password: process.env.DB_PASS,
    database: process.env.DB_NAME,
    dialect: 'mysql',
    dialectOptions: {
      socketPath: `${dbSocketPath}/${process.env.INSTANCE_CONNECTION_NAME}`
    }
  })

  const e = await casbin.newEnforcer('rbac_model.conf', a)
  return e
}

class Casbin {
  async addPolicies (rules) {
    // Check the permission.

    // Modify the policy.
    // await e.addPolicy(...);
    // await e.removePolicy(...);
    const e = await returnEnforcer()
    const added = await e.addNamedPolicies('p', rules)

    return added

    // Save the policy back to DB.
    // await e.savePolicy();
  }

  async removePolicies (rules) {
    const e = await returnEnforcer()
    const removed = await e.removeNamedPolicies('p', rules)
    return removed
  }

  async getPolicy (clientProjectFilter = null) {
    const e = await returnEnforcer()
    const policy = await e.getPolicy()
    return policy
  }
  async enforce (request) {
    const e = await returnEnforcer()
    return e.enforce(request.sub, request.dom, request.obj, request.act)
  }

**Issue with this is that it creates a new connection each time i call above functions from respective APIs, but somehow i need to understand if i can use my global connection pool already created for other modules as well. Or atleast a pool can be created dedicated for casbin interaction with mysql.

Please let me know if i am thinking on the correct lines and if above is possible then how can i achieve the connection pool so that i can optimize my connections with sql

hsluoyz commented 4 years ago

@nodece @zhmushan can you answer this question?

zhmushan commented 4 years ago

You can set the adapter as a global variable. e.g.:

const a = await SequelizeAdapter.newAdapter(...);

function returnEnforcer () {
  return casbin.newEnforcer('rbac_model.conf', a);
}
...
nodece commented 4 years ago

You are creating too many enforcer, the best way is inject enforcer to Casbin, look like:

class Casbin {
  constructor(e) {
    this.e = e;
  }

  async addPolicies (rules) {
    // Check the permission.

    // Modify the policy.
    // await e.addPolicy(...);
    // await e.removePolicy(...);
    const added = await this.e.addNamedPolicies('p', rules)

    return added

    // Save the policy back to DB.
    // await this.e..savePolicy();
  }

  async removePolicies (rules) {
    const removed = await this.e.removeNamedPolicies('p', rules)
    return removed
  }

  async getPolicy (clientProjectFilter = null) {
    const policy = await this.e.getPolicy()
    return policy
  }
  async enforce (request) {
    return this.e.enforce(request.sub, request.dom, request.obj, request.act)
  }
}

const e = await returnEnforcer()
const casbin = new Casbin(e)
puneetjindal commented 4 years ago

Thanks for really quick response. it works!