0.2.3 • Published 4 years ago

simple-authorization v0.2.3

Weekly downloads
43
License
MIT
Repository
github
Last release
4 years ago

Simple Authorization

Build Status Code Climate Test Coverage

Simple Authorization is a JavaScript library inspired by Pundit for performing user authorization using simple JavaScript classes. If you've used Pundit in a Ruby project, you'll be instantly familiar.

Installation

Install the package via Yarn:

yarn add simple-authorization

Configuration

Initialize Simple Authorization to configure the data made available to your policy classes, and configure the policy class to use based on the name of the model that's being authorized.

import CommentPolicy from "../policies/comment-policy";
import PostPolicy from "../policies/post-policy";
import SimpleAuthorization from "simple-authorization";

// Assign a function that will return the data you need in
// each of your policies to make authorization decisions.
SimpleAuthorization.policyData = () => {
  const currentUser = { id: 5 };
  const role = {
    createPost: true,
    editOwnPost: true,
    editOthersPost: false
  };

  return { currentUser, role };
};

// Assign a function that will return your
// policy class based on the given model name.
SimpleAuthorization.policyResolver = modelName => {
  switch (modelName) {
    case "Comment":
      return CommentPolicy;
    case "Post":
      return PostPolicy;
  }
};

Usage

Create a base policy class to assign the data passed into the constructor to make it available to each policy.

class ApplicationPolicy {
  /**
   * Initializes the policy instance with the required data.
   *
   * @param {object} policyData The data needed for all policies
   */
  constructor({ currentUser, record, role }) {
    this.currentUser = currentUser;
    this.record = record;
    this.role = role;
  }
}

Create your policy class with the methods needed to determine whether the user is permitted to perform an action.

class PostPolicy extends ApplicationPolicy {
  /**
   * Permission to create a blog post.
   *
   * @returns {boolean} Whether the user is permitted
   */
  create() {
    return this.role.createPost;
  }

  /**
   * Permission to edit a blog post. In this example, we need to
   * know if the post was created by the current user or another
   * user when checking the user's permissions.
   *
   * `this.record` is the object we're passing in when calling `policy()`.
   *
   * @returns {boolean} Whether the user is permitted
   */
  edit() {
    if (this.record.userId === this.currentUser.id) {
      return this.role.editOwnPost;
    }

    return this.role.editOthersPost;
  }
}

The policies can be used in multiple ways by using the policy() helper method. The policy class that is used is determined by the SimpleAuthorization.policyResolver function we defined in the configuration step.

import { policy } from "simple-authorization";

// This will initialize the PostPolicy class with the data passed in from
// the return value of the `SimpleAuthorization.policyData` function.
policy("Post").create();
// => true

const post = new Post({ userId: 10 });

// This will also initialize the PostPolicy class because of the post
// instance's constructor name, and it will also make the post instance
// available as `this.record` in the PostPolicy `edit` method.
policy(post).edit();
// => false

// If you don't have an instance of a class, you can still make a plain
// object available as `this.record`.
policy("Post", { userId: 5 }).edit();
// => true

React

Simple Authorization also includes an <Authorize> React component for wrapping items that should be conditionally displayed based on the user's permissions.

import { Authorize } from "simple-authorization";

export default props => {
  return (
    <div>
      <Authorize perform="create" on="Post">
        <button>New Post</button>
      </Authorize>

      <Authorize perform="edit" on={new Post({ userId: 10 })}>
        <button>Edit Post</button>
      </Authorize>

      <Authorize perform="edit" on="Post" containing={{ userId: 5 }}>
        <button>Edit Post</button>
      </Authorize>
    </div>
  );
};

Because the SimpleAuthorization.policyData function isn't aware of when the data returned changes, the <Authorize> component keeps track of each of the mounted instances so they can be forced to render when your policy data changes.

import { Authorize } from "simple-authorization";
import store from "./store"; // Redux store

let currentUserRole;
store.subscribe(() => {
  let previousUserRole = currentUserRole;
  currentUserRole = store.getState().userRole;

  if (previousUserRole !== currentUserRole) {
    Authorize.forceUpdateAll();
  }
});

If you're looking to render markup for when a user is not permitted to perform an action, simply add cannot.

import { Authorize } from "simple-authorization";

export default props => {
  return (
    <Authorize cannot perform="create" on="Post">
      <div>You are not authorized to create new posts.</div>
    </Authorize>
  );
};

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

License

This module is available as open source under the terms of the MIT License.

0.2.3

4 years ago

0.2.2

4 years ago

0.2.1

4 years ago

0.2.0

4 years ago

0.1.6

4 years ago

0.1.5

5 years ago

0.1.4

5 years ago

0.1.3

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago