@loopback/authorization
Version:
A LoopBack component for authorization support.
162 lines • 6.01 kB
JavaScript
;
// Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
// Node module: @loopback/authorization
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAuthorizationMetadata = exports.authorize = exports.AuthorizeMethodDecoratorFactory = exports.AUTHORIZATION_CLASS_KEY = exports.AUTHORIZATION_METHOD_KEY = void 0;
const core_1 = require("@loopback/core");
const types_1 = require("../types");
exports.AUTHORIZATION_METHOD_KEY = core_1.MetadataAccessor.create('authorization:method');
exports.AUTHORIZATION_CLASS_KEY = core_1.MetadataAccessor.create('authorization:class');
class AuthorizeClassDecoratorFactory extends core_1.ClassDecoratorFactory {
}
class AuthorizeMethodDecoratorFactory extends core_1.MethodDecoratorFactory {
mergeWithOwn(ownMetadata, target, methodName,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
methodDescriptor) {
ownMetadata = ownMetadata || {};
let methodMeta = ownMetadata[methodName];
if (!methodMeta) {
methodMeta = { ...this.spec };
ownMetadata[methodName] = methodMeta;
}
if (this.spec.allowedRoles) {
methodMeta.allowedRoles = this.merge(methodMeta.allowedRoles, this.spec.allowedRoles);
}
if (this.spec.deniedRoles) {
methodMeta.deniedRoles = this.merge(methodMeta.deniedRoles, this.spec.deniedRoles);
}
if (this.spec.scopes) {
methodMeta.scopes = this.merge(methodMeta.scopes, this.spec.scopes);
}
if (this.spec.voters) {
methodMeta.voters = this.merge(methodMeta.voters, this.spec.voters);
}
return ownMetadata;
}
merge(src, target) {
const list = [];
if (src === target)
return src !== null && src !== void 0 ? src : list;
const set = new Set(src !== null && src !== void 0 ? src : []);
if (target) {
for (const i of target) {
set.add(i);
}
}
for (const i of set.values())
list.push(i);
return list;
}
}
exports.AuthorizeMethodDecoratorFactory = AuthorizeMethodDecoratorFactory;
/**
* Decorator `@authorize` to mark methods that require authorization
*
* @param spec Authorization metadata
*/
function authorize(spec) {
return function authorizeDecoratorForClassOrMethod(
// Class or a prototype
// eslint-disable-next-line @typescript-eslint/no-explicit-any
target, method,
// Use `any` to for `TypedPropertyDescriptor`
// See https://github.com/loopbackio/loopback-next/pull/2704
// eslint-disable-next-line @typescript-eslint/no-explicit-any
methodDescriptor) {
if (method && methodDescriptor) {
// Method
return AuthorizeMethodDecoratorFactory.createDecorator(exports.AUTHORIZATION_METHOD_KEY, spec, { decoratorName: '@authorize' })(target, method, methodDescriptor);
}
if (typeof target === 'function' && !method && !methodDescriptor) {
// Class
return AuthorizeClassDecoratorFactory.createDecorator(exports.AUTHORIZATION_CLASS_KEY, spec, { decoratorName: '@authorize' })(target);
}
// Not on a class or method
throw new Error('@intercept cannot be used on a property: ' +
core_1.DecoratorFactory.getTargetName(target, method, methodDescriptor));
};
}
exports.authorize = authorize;
(function (authorize) {
/**
* Shortcut to configure allowed roles
* @param roles
*/
authorize.allow = (...roles) => authorize({ allowedRoles: roles });
/**
* Shortcut to configure denied roles
* @param roles
*/
authorize.deny = (...roles) => authorize({ deniedRoles: roles });
/**
* Shortcut to specify access scopes
* @param scopes
*/
authorize.scope = (...scopes) => authorize({ scopes });
/**
* Shortcut to configure voters
* @param voters
*/
authorize.vote = (...voters) => authorize({ voters });
/**
* Allows all
*/
authorize.allowAll = () => authorize.allow(types_1.EVERYONE);
/**
* Allow all but the given roles
* @param roles
*/
authorize.allowAllExcept = (...roles) => authorize({
deniedRoles: roles,
allowedRoles: [types_1.EVERYONE],
});
/**
* Deny all
*/
authorize.denyAll = () => authorize.deny(types_1.EVERYONE);
/**
* Deny all but the given roles
* @param roles
*/
authorize.denyAllExcept = (...roles) => authorize({
allowedRoles: roles,
deniedRoles: [types_1.EVERYONE],
});
/**
* Allow authenticated users
*/
authorize.allowAuthenticated = () => authorize.allow(types_1.AUTHENTICATED);
/**
* Deny unauthenticated users
*/
authorize.denyUnauthenticated = () => authorize.deny(types_1.UNAUTHENTICATED);
/**
* Skip authorization
*/
authorize.skip = () => authorize({ skip: true });
})(authorize || (exports.authorize = authorize = {}));
/**
* Fetch authorization metadata stored by `@authorize` decorator.
*
* @param target Target object/class
* @param methodName Target method
*/
function getAuthorizationMetadata(target, methodName) {
let targetClass;
if (typeof target === 'function') {
targetClass = target;
target = target.prototype;
}
else {
targetClass = target.constructor;
}
const metadata = core_1.MetadataInspector.getMethodMetadata(exports.AUTHORIZATION_METHOD_KEY, target, methodName);
if (metadata)
return metadata;
// Check if the class level has `@authorize`
return core_1.MetadataInspector.getClassMetadata(exports.AUTHORIZATION_CLASS_KEY, targetClass);
}
exports.getAuthorizationMetadata = getAuthorizationMetadata;
//# sourceMappingURL=authorize.js.map