Skip to content
Branch: master
Find file History
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
..
Failed to load latest commit information.
fixtures/casbin
src
.npmrc
CHANGELOG.md
LICENSE
README.md
authorization.png
index.d.ts
index.js
index.ts
package-lock.json
package.json
tsconfig.build.json

README.md

@loopback/authorization

A LoopBack 4 component for authorization support.

Overview

Authorization decides if a subject can perform specific action on an object.

Authorization

Role based

Permission based

Vote based

Key building blocks

  1. Decorate a method to describe:
  • Permission (maps the method to an action on the protected resource)

    • Type of the protected resource (such as customer or order)
    • What action does the method represent (such as changeEmail, createOrder, or cancelOrder)
  • ACL (provides role based rules)

    • allowedRoles
    • deniedRoles
  • Voters (supplies a list of function to vote on the decision)

  1. Intercept a method invocation
  • Build authorization context

    • Subject (who) - from authentication
    • Map principals to roles
    • Inspect the target method for metadata - Permission, ACL, voters
  • Run through voters/enforcers to make decisions

Decision matrix

The final decision is controlled by voting results from authorizers and options for the authorization component.

The following table illustrates the decision matrix with 3 voters and corresponding options.

Vote #1 Vote # 2 Vote #3 Options Final Decision
Deny Deny Deny any Deny
Allow Allow Allow any Allow
Abstain Allow Abstain any Allow
Abstain Deny Abstain any Deny
Deny Allow Abstain {precedence: Deny} Deny
Deny Allow Abstain {precedence: Allow} Allow
Allow Abstain Deny {precedence: Deny} Deny
Allow Abstain Deny {precedence: Allow} Allow
Abstain Abstain Abstain {defaultDecision: Deny} Deny
Abstain Abstain Abstain {defaultDecision: Allow} Allow

The options is described as follows:

export interface AuthorizationOptions {
  /**
   * Default decision if all authorizers vote for ABSTAIN
   */
  defaultDecision?: AuthorizationDecision.DENY | AuthorizationDecision.ALLOW;
  /**
   * Controls if Allow/Deny vote takes precedence and override other votes
   */
  precedence?: AuthorizationDecision.DENY | AuthorizationDecision.ALLOW;
}

The authorization component can be configured with options:

const options: AuthorizationOptions = {
  precedence: AuthorizationDecisions.DENY;
  defaultDecision: AuthorizationDecisions.DENY;
}

const binding = app.component(AuthorizationComponent);
app.configure(binding.key).to(options);

Installation

npm install --save @loopback/authorization

Basic use

Start by decorating your controller methods with @authorize to require the request to be authorized.

In this example, we make the user profile available via dependency injection using a key available from @loopback/authorization package.

import {inject} from '@loopback/context';
import {authorize} from '@loopback/authorization';
import {get} from '@loopback/rest';

export class MyController {
  @authorize({allow: ['ADMIN']})
  @get('/number-of-views')
  numOfViews(): number {
    return 100;
  }
}

Extract common layer(TBD)

@loopback/authentication and @loopback/authorization shares the client information from the request. Therefore we need another module with types/interfaces that describe the client, like principles, userProfile, etc... A draft PR is created for this module: see branch https://github.com/strongloop/loopback-next/tree/security/packages/security

Since the common module is still in progress, as the first release of @loopback/authorization, we have two choices to inject a user in the interceptor:

  • @loopback/authorization requires @loopback/authentication as a dependency. The interceptor injects the current user using AuthenticationBindings.CURRENT_USER. Then we remove this dependency in the common layer PR, two auth modules will depend on @loopback/security.

    • This is what's been done in my refactor PR, Principle and UserProfile are still decoupled, I added a convertor function to turn a user profile into a principle.
  • The interceptor injects the user using another key not related to @loopback/authentication.(Which means the code that injects the user stays as it is in https://github.com/strongloop/loopback-next/pull/1205). Then we unify the user set and injection in the common layer PR: same as the 1st choice, two auth modules will depend on @loopback/security.

Related resources

Contributions

Tests

run npm test from the root folder.

Contributors

See all contributors.

License

MIT

You can’t perform that action at this time.