{"id":18356507,"url":"https://github.com/lbwa/v-access","last_synced_at":"2025-04-06T12:32:16.425Z","repository":{"id":35095059,"uuid":"202139107","full_name":"lbwa/v-access","owner":"lbwa","description":"🔐An authentication plugin based on Vue.js v2.x, including elements-based control and route-based control.","archived":false,"fork":false,"pushed_at":"2023-01-04T21:58:32.000Z","size":620,"stargazers_count":11,"open_issues_count":5,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-24T23:20:52.403Z","etag":null,"topics":["access-control","authorization","element-access-control","element-authentication","routes-access-control","routes-authentication","routes-protection","vue","vue-router"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lbwa.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-13T12:25:51.000Z","updated_at":"2023-03-12T11:49:03.000Z","dependencies_parsed_at":"2023-01-15T13:44:26.432Z","dependency_job_id":null,"html_url":"https://github.com/lbwa/v-access","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lbwa%2Fv-access","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lbwa%2Fv-access/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lbwa%2Fv-access/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lbwa%2Fv-access/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lbwa","download_url":"https://codeload.github.com/lbwa/v-access/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247484474,"owners_count":20946388,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["access-control","authorization","element-access-control","element-authentication","routes-access-control","routes-authentication","routes-protection","vue","vue-router"],"created_at":"2024-11-05T22:10:30.321Z","updated_at":"2025-04-06T12:32:15.930Z","avatar_url":"https://github.com/lbwa.png","language":"TypeScript","readme":"\u003ch1 align=\"center\"\u003ev-access\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/v-access\"\u003e\n    \u003cimg alt=\"npm bundle size\" src=\"https://img.shields.io/bundlephobia/minzip/v-access?logo=webpack\u0026style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/v-access\"\u003e\n    \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/dt/v-access?logo=Vue.js\u0026style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/v-access\"\u003e\n    \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/v/v-access?logo=npm\u0026style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/v-access\"\u003e\n    \u003cimg alt=\"npm type definitions\" src=\"https://img.shields.io/npm/types/v-access?logo=typescript\u0026style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/lbwa/v-access/actions\"\u003e\n    \u003cimg alt=\"tests\" src=\"https://github.com/lbwa/v-access/workflows/Tests/badge.svg\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003e An authentication solution based on Vue.js v2.x, including **elements-based** control and **route-based** control.\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"./README.zh-cn.md\"\u003e中文指南\u003c/a\u003e | English\n\u003c/p\u003e\n\n|                      Dependencies                      | Required |\n| :----------------------------------------------------: | :------: |\n|        [vue](https://www.npmjs.com/package/vue)        |    ✔️    |\n| [vue-router](https://www.npmjs.com/package/vue-router) |    ✔️    |\n\n## Features\n\n- **Minimal design**: Only one _ability/privilege_ list and give you all **element-based** and **route-based** authentications.\n\n- **Smooth changes**: Support any dynamic private routes addition and deletion **without page reloading**.\n\n## Installation\n\n```bash\n# using npm\nnpm i v-access\n\n# using yarn\nyarn add v-access\n```\n\n## Prerequisites\n\n- Ability type\n\n  ```ts\n  type Ability = string\n  ```\n\n  `Ability` should be a **global unique** identifier and _string_ type.\n\n- Routes type\n\n  ```ts\n  interface RouteWithAbility extends RouteConfig {\n    readonly children?: RouteWithAbility[]\n    readonly meta?: {\n      strict?: Ability[]\n      weak?: Ability[]\n      ability?: Ability\n      [key: string]: any\n    }\n  }\n  ```\n\n  More details could be found from [here](#Initialization).\n\n### Best practice\n\n\u003e NOTICE: This section is only the best practice **recommendation, not required**.\n\nThe entire authorization system is based on **an ability/privilege list** provided by any back-end services. Every element in the list represents an ability that is used to access the corresponding database. A _user role_ consists of multiple abilities, represents an _ability set_. One actual user could have multiple user roles.\n\nThere is a best practice that uses syntax like `[scope].[module].[ability]` (eg. [IAM](https://cloud.google.com/storage/docs/access-control/iam)) to represents one ability. In this case, `[scope]` is optional if you have no other external systems (scope).\n\nThe advantage of this design is that the role of multiple users or the ability of multiple roles can be intersected. Multiple abilities can be arbitrarily combined to form a **flexible abilities set**.\n\nThe following chart represents an actual user's ability set:\n\n```\n                      +--\u003e github.repo.read\n      +-\u003e user role 1 |\n      |               +--\u003e npm.org.import\n      |\n      |               +--\u003e github.pull.read\nuser -+-\u003e user role 2 |\n      |               +--\u003e npm.downloads.read\n      |\n      |               +--\u003e github.action.read\n      +-\u003e user role 3 |\n                      +--\u003e npm.packages.publish\n```\n\nNo matter what your ability name is, you should always call [init](#Initialization) function with a full ability list first.\n\n## Initialization\n\n```ts\nimport Vue from 'vue'\nimport VAccess from 'v-access'\n\nVue.use(VAccess)\n```\n\nThis package should be installed **before** the root Vue instance creation. This process will inject a global component named `VAccess` and a prototype property named `$$auth`.\n\n```ts\nimport { init } from 'v-access'\n\nexport default {\n  name: 'AnyComponent',\n\n  // ... omit all unrelated properties\n\n  created() {\n    // a vuex action or http request\n    fetchAbilities(payload)\n      .then(list =\u003e list.map(abilityInfo =\u003e ability.name)) // ability serialization\n      .then(abilities =\u003e\n        init({\n          vm: this, // or this.$router\n          abilities,\n          redirect: '/forbidden',\n          routes: [\n            /* routes which need to add to vue-router would be filtered by abilities first */\n          ]\n        })\n      )\n      .catch(console.error)\n  }\n}\n```\n\nNo matter the original abilities structure is, you should always pass an `Ability identity` list (a `string[]` type) to `init` function for initializing global authentication functionality.\n\n```ts\ninterface InitOptions {\n  vm: Vue | VueRouter\n  abilities: Ability[]\n  redirect: string\n  routes?: RouteWithAbility[]\n}\n\nexport declare function init({\n  vm,\n  abilities,\n  redirect,\n  routes\n}: InitOptions): void\n```\n\nNOTE: `redirect` only support a [fullPath](https://router.vuejs.org/api/#route-object-properties) string, not object type.\n\nAs you may have noticed, you can pass a global preset private routes collection to `init` function for dynamic routes addition. All valid private routes generation could be handled by this package and will be filtered by `abilities` set.\n\n### Scenario\n\nThis case would be useful when you want to create private routes that need to be filtered by the current user abilities.\n\n## How to authenticate ability\n\n1. Using `element-based` authentication\n\n   The results of the following two authentication ways are **reactive**.\n\n   1. `VAccess` component\n\n      ```html\n      \u003cv-access :ability=\"['github.repo.read', 'github.repo.pull']\"\u003e\n        \u003c!-- any child components or HTML nodes --\u003e\n      \u003c/v-access\u003e\n\n      \u003c!-- or --\u003e\n      \u003cv-access strict :ability=\"['github.repo.read', 'github.repo.pull']\"\u003e\n        \u003c!-- any child components or HTML nodes --\u003e\n      \u003c/v-access\u003e\n\n      \u003c!-- or --\u003e\n      \u003cv-access :ability=\"github.repo.read\"\u003e\n        \u003c!-- any child components or HTML nodes --\u003e\n      \u003c/v-access\u003e\n      ```\n\n      |  Props  |           Type           |                        Description                         |\n      | :-----: | :----------------------: | :--------------------------------------------------------: |\n      | ability | `Ability` or `Ability[]` |  An ability or ability set that needs to be authenticated  |\n      | strict  |        `boolean`         | Whether we should authenticate every abilities in the list |\n\n   1. `$$auth` object\n\n      The following table describes several `$$auth` authentication functions.\n\n      |  Function  |                Type                 |                           Description                           |\n      | :--------: | :---------------------------------: | :-------------------------------------------------------------: |\n      |    has     |   `(ability: Ability) =\u003e boolean`   |            An ability that needs to be authenticated            |\n      | verifyAll  | `(abilities: Ability[]) =\u003e boolean` |    Whether we should authenticate every ability in the list     |\n      | verifySome | `(abilities: Ability[]) =\u003e boolean` | Whether we should authenticate at least one ability in the list |\n\n1. Using `route-based` authentication\n\n   ```ts\n   const routes = [\n     // This route always pass authentication\n     {\n       name: 'PublicRoutes',\n       path: '/public',\n       component: () =\u003e\n         import(/* webpackChunkName: 'page-public' */ './views/Public.vue')\n     },\n     {\n       name: 'PrivateRoutes',\n       path: '/private',\n       component: () =\u003e\n         import(/* webpackChunkName: 'page-private' */ './views/Private.vue'),\n       meta: {\n         strict: ['github.repo.read', 'github.repo.pull']\n         // or\n         // weak: ['github.repo.read', 'github.repo.pull'],\n         // or\n         // ability: 'github.repo.read'\n       }\n     }\n   ]\n   ```\n\n   | Meta prop |                            Objective                            |\n   | :-------: | :-------------------------------------------------------------: |\n   | `strict`  |    Whether we should authenticate every ability in the list     |\n   |  `weak`   | Whether we should authenticate at least one ability in the list |\n   | `ability` |         A single ability that needs to be authenticated         |\n\n## Reset\n\n```ts\nexport declare function reset(router: VueRouter): void\n```\n\nYou should always use `reset(theCurrentRouterInstance)` to delete all private routes added by `init` function without any page reloading.\n\n```ts\nimport { reset } from 'v-access'\n\nreset(this.$router)\n```\n\n## With other hooks\n\n[Separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) is a design principle for separating distinct parts, and implement the high cohesion and low coupling between multiple independent parts. [Vue router navigation guard][doc-router-beforeeach] accepts **multiple** hooks to implement a navigation pipeline via this principle. This is the theoretical basis for `v-access` implementation. `v-access` has provided an `authorizer` as a `beforeEach` guard.\n\nIf you aren't familiar with how multiple global `beforeEach` hooks work, I strongly recommend you to read [the documentation][doc-router-beforeeach] about `router.beforeEach`.\n\n[doc-router-beforeeach]: https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards\n\n## Changelog\n\nAll notable changes to this package will be documented in [CHANGELOG](./CHANGELOG.md) file.\n\n## License\n\nMIT © [Bowen Liu](https://github.com/lbwa)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flbwa%2Fv-access","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flbwa%2Fv-access","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flbwa%2Fv-access/lists"}