Access Control
For frontend applications, "access control" refers to whether pages are accessible and whether page elements are visible.
Setup
- Install the plugin
$ npm add @winner-fed/plugin-access -D
$ yarn add @winner-fed/plugin-access -D
$ pnpm add @winner-fed/plugin-access -D
$ bun add @winner-fed/plugin-access -D
- Enable the plugin in the
.winrc
configuration file
import { defineConfig } from 'win';
export default defineConfig({
plugins: ['@winner-fed/plugin-access'],
routes: [{
path: '/',
name: 'Home',
component: 'index',
routes: [
{
path: 'admin',
name: 'Admin',
component: '@/components/admin'
},
{
path: 'normal',
name: 'Normal',
component: '@/components/normal'
}
]
}],
/**
* @name Access Control Plugin
* @doc https://winjs-dev.github.io/winjs-docs/plugins/access.html
*/
access: {
roles: {
admin: ['/admin'],
normal: ['/normal']
}
}
});
Introduction
In this plugin design, one page permission corresponds to one route. For example, when accessing the '/admin'
route, if the current role doesn't have permission for this route, the component will not be rendered.
export default {
access: {
roles: {
admin: ['/admin'],
normal: ['/normal']
}
}
};
Usage example:
<template>
<Access :id="accessId">Only visible to Admin</Access>
<div v-access="accessId">Only visible to Admin</div>
</template>
<script setup lang="ts">
const accessId = '/admin';
</script>
Note
We uniformly refer to pages and page elements as resources, and use resource IDs to identify and distinguish them:
- The resource ID of a page defaults to the page's route
path
. For example, the routepath
of pagepages/a.vue
is/a
. When the page accesses/a
, the current page will be rendered, and/a
is the page'saccessId
. - Page elements' resource IDs have no default value and need to be customized.
Matching Rules
Exact Matching
The default matching rule for resources is exact matching. For example, if page pages/a.vue
corresponds to route path
/a
, then /a
is the page's resource ID. If we set:
access.setAccess(['/a']);
Since the permission list contains /a
, it indicates having permission for this page.
Fuzzy Matching
Page @id.vue
will be mapped to dynamic route /:id
. There are two ways to match this page:
- access.setAccess(['/:id'])
- access.setAccess(['/*'])
The second is fuzzy matching, where *
represents any path. For example, if role admin
needs full permissions:
export default {
access: {
roles: {
admin: ['*']
}
}
};
Compile-time Configuration
When executing win dev
or win build
, runtime code is generated through this configuration. Configure in the .winrc.js
configuration file:
export default {
access: {
roles: {
admin: ['/', '/admin', '/normal'],
},
},
};
roles
Type:
Record<string, []>;
Default:
{}
Details:
Predefined role list.
key
is the role ID, andvalue
is the resource list corresponding to the role ID.
Runtime Configuration
Configure in app.js
unAccessHandler
Type:
Function
Default:
null
Details: When entering a route, if the page corresponding to the route doesn't belong to the visible resource list, entry will be paused and the
unAccessHandler
function will be called.Parameters
- router: Router instance created by createRouter
- to: Route being navigated to
- from: Route being navigated away from
- next: next function
Example:
import { access as accessApi } from 'winjs';
export const access = {
unAccessHandler ({ to, next }) {
const accesssIds = accessApi.getAccess();
if (to.path === '/404') {
accessApi.setAccess(accesssIds.concat(['/404']));
return next('/404');
}
if (!accesssIds.includes('/403')) {
accessApi.setAccess(accesssIds.concat(['/403']));
}
next('/403');
},
};
noFoundHandler
- Type:
Function
- Default:
null
- Details: When entering a route, if the page corresponding to the route doesn't exist, the
noFoundHandler
function will be called. - Parameters
- router: Router instance created by createRouter
- to: Route being navigated to
- from: Route being navigated away from
- next: next function
Example:
import { access as accessApi } from 'winjs';
export const access = {
noFoundHandler ({ next }) {
const accesssIds = accessApi.getAccess();
if (!accesssIds.includes('/404')) {
accessApi.setAccess(accesssIds.concat(['/404']));
}
next('/404');
},
};
ignoreAccess
- Type:
Array<string>
- Default:
null
- Details: Configure pages that should ignore access control validation.
Example:
export const access = {
ignoreAccess: ['/login'],
};
API
WinJS uses custom directives, specifically the v-access
directive, passing in the object returned by useAccess to control component rendering.
Plugin APIs are exported through winjs
:
import { access } from 'winjs';
access.hasAccess
- Type:
( accessId: string | number ) => Promise\<boolean\>
- Details: Determine whether a resource is visible.
- Parameters:
- accessId: Resource ID
- Returns: Whether access is granted
access.isDataReady
- Type:
() => boolean
- Details: Permissions can be set using asynchronous data.
isDataReady
is used to determine whether asynchronous data has finished loading. - Parameters: null
- Returns: Boolean
import { access } from 'winjs';
console.log(access.isDataReady());
access.setRole
- Type:
Function
- Details: Set the current role.
- Parameters:
- roleId: Role ID, has two types:
- String: Corresponds to the
key
in theroles
configuration object. - Promise: The result of Promise resolve should correspond to the
key
in theroles
configuration object.
- String: Corresponds to the
import { access } from 'winjs';
access.setRole('admin');
access.getRole
- Type:
Function
- Details: Get the current role.
import { access } from 'winjs';
access.getRole();
access.setAccess
- Type:
Function
- Details: Set the current access permissions.
- Parameters:
- accessIds: Array of resource IDs, has two types:
- Array: Array items correspond to the
key
in theroles
configuration object. - Promise: The result of Promise resolve should be
Array<accessId>
.
- Array: Array items correspond to the
import { access } from 'winjs';
access.setAccess(['/a', '/b', '/c']);
access.getAccess
- Type:
Function
- Details: Return the current list of visible resources.
- Parameters: null
import { access } from 'winjs';
access.getAccess();
useAccess
- Type: Composition function
- Details: Determine whether a resource is visible.
- Parameters:
- accessId: Resource ID
- Returns:
ref
<template>
<div v-if="accessOnepicess">accessOnepicess</div>
</template>
<script>
import { useAccess } from 'winjs';
export default {
setup () {
const accessOnepicess = useAccess('/onepiece1');
return {
accessOnepicess,
};
},
};
</script>
v-access
Pass accessId
into the v-access
directive. When accessId
has permission, the DOM will be displayed; when there's no permission, the DOM will be hidden.
<template>
<div v-access="accessId">accessOnepicess</div>
</template>
<script>
export default {
setup () {
return {
accessId: 'accessOnepicess',
};
},
};
</script>
Access Component
Pass accessId
into the Access
component. When accessId
has permission, this component will be rendered; when there's no permission, this component will be hidden.
<template>
<access :id="accessId"> accessOnepicess</access>
</template>
<script>
export default {
setup () {
return {
accessId: 'accessOnepicess',
};
},
};
</script>