v-access v2.1.1
An authentication solution based on Vue.js v2.x, including elements-based control and route-based control.
| Dependencies | Required |
|---|---|
| vue | ✔️ |
| vue-router | ✔️ |
Features
Minimal design: Only one ability/privilege list and give you all element-based and route-based authentications.
Smooth changes: Support any dynamic private routes addition and deletion without page reloading.
Installation
# using npm
npm i v-access
# using yarn
yarn add v-accessPrerequisites
Ability type
type Ability = stringAbilityshould be a global unique identifier and string type.Routes type
interface RouteWithAbility extends RouteConfig { readonly children?: RouteWithAbility[] readonly meta?: { strict?: Ability[] weak?: Ability[] ability?: Ability [key: string]: any } }More details could be found from here.
Best practice
NOTICE: This section is only the best practice recommendation, not required.
The 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.
There is a best practice that uses syntax like [scope].[module].[ability] (eg. IAM) to represents one ability. In this case, [scope] is optional if you have no other external systems (scope).
The 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.
The following chart represents an actual user's ability set:
+--> github.repo.read
+-> user role 1 |
| +--> npm.org.import
|
| +--> github.pull.read
user -+-> user role 2 |
| +--> npm.downloads.read
|
| +--> github.action.read
+-> user role 3 |
+--> npm.packages.publishNo matter what your ability name is, you should always call init function with a full ability list first.
Initialization
import Vue from 'vue'
import VAccess from 'v-access'
Vue.use(VAccess)This 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.
import { init } from 'v-access'
export default {
name: 'AnyComponent',
// ... omit all unrelated properties
created() {
// a vuex action or http request
fetchAbilities(payload)
.then(list => list.map(abilityInfo => ability.name)) // ability serialization
.then(abilities =>
init({
vm: this, // or this.$router
abilities,
redirect: '/forbidden',
routes: [
/* routes which need to add to vue-router would be filtered by abilities first */
]
})
)
.catch(console.error)
}
}No 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.
interface InitOptions {
vm: Vue | VueRouter
abilities: Ability[]
redirect: string
routes?: RouteWithAbility[]
}
export declare function init({
vm,
abilities,
redirect,
routes
}: InitOptions): voidNOTE: redirect only support a fullPath string, not object type.
As 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.
Scenario
This case would be useful when you want to create private routes that need to be filtered by the current user abilities.
How to authenticate ability
Using
element-basedauthenticationThe results of the following two authentication ways are reactive.
VAccesscomponent<v-access :ability="['github.repo.read', 'github.repo.pull']"> <!-- any child components or HTML nodes --> </v-access> <!-- or --> <v-access strict :ability="['github.repo.read', 'github.repo.pull']"> <!-- any child components or HTML nodes --> </v-access> <!-- or --> <v-access :ability="github.repo.read"> <!-- any child components or HTML nodes --> </v-access>Props Type Description ability AbilityorAbility[]An ability or ability set that needs to be authenticated strict booleanWhether we should authenticate every abilities in the list $$authobjectThe following table describes several
$$authauthentication functions.Function Type Description has (ability: Ability) => booleanAn ability that needs to be authenticated verifyAll (abilities: Ability[]) => booleanWhether we should authenticate every ability in the list verifySome (abilities: Ability[]) => booleanWhether we should authenticate at least one ability in the list
Using
route-basedauthenticationconst routes = [ // This route always pass authentication { name: 'PublicRoutes', path: '/public', component: () => import(/* webpackChunkName: 'page-public' */ './views/Public.vue') }, { name: 'PrivateRoutes', path: '/private', component: () => import(/* webpackChunkName: 'page-private' */ './views/Private.vue'), meta: { strict: ['github.repo.read', 'github.repo.pull'] // or // weak: ['github.repo.read', 'github.repo.pull'], // or // ability: 'github.repo.read' } } ]Meta prop Objective strictWhether we should authenticate every ability in the list weakWhether we should authenticate at least one ability in the list abilityA single ability that needs to be authenticated
Reset
export declare function reset(router: VueRouter): voidYou should always use reset(theCurrentRouterInstance) to delete all private routes added by init function without any page reloading.
import { reset } from 'v-access'
reset(this.$router)With other hooks
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 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.
If you aren't familiar with how multiple global beforeEach hooks work, I strongly recommend you to read the documentation about router.beforeEach.
Changelog
All notable changes to this package will be documented in CHANGELOG file.
License
MIT © Bowen Liu