├── .browserslistrc
├── public
├── favicon.ico
└── index.html
├── publish.sh
├── src
├── shims-vue.d.ts
├── main.ts
├── Authorized
│ ├── type.ts
│ ├── reactive.ts
│ ├── index.ts
│ ├── Authorized.vue
│ └── utils.ts
├── App.vue
└── __tests__
│ └── index.spec.js
├── .gitignore
├── .github
└── workflows
│ └── ci.yml
├── scripts
└── release.js
├── tsconfig.json
├── jest.config.js
├── LICENSE
├── package.json
└── README.md
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xjh22222228/vue-authorized/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/publish.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 |
3 | # npm 发布
4 | # sudo ./publish.sh
5 |
6 | yarn build && yarn release
7 |
8 | cd dist && npm publish
9 |
10 | rm -rf ../dist
11 |
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import type { DefineComponent } from 'vue'
3 | const component: DefineComponent<{}, {}, any>
4 | export default component
5 | }
6 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | // Copyright 2021 the vue-authorized authors. All rights reserved. MIT license.
2 |
3 | import { createApp } from 'vue'
4 | import App from './App.vue'
5 |
6 | createApp(App).mount('#app')
7 |
--------------------------------------------------------------------------------
/src/Authorized/type.ts:
--------------------------------------------------------------------------------
1 | // Copyright 2021 the vue-authorized authors. All rights reserved. MIT license.
2 |
3 | export type IReactive = {
4 | value: unknown[]
5 | hasPermission: boolean
6 | }
7 |
8 | export type IAuthority =
9 | | string
10 | | number
11 | | unknown[]
12 | | null
13 | | undefined
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/Authorized/reactive.ts:
--------------------------------------------------------------------------------
1 | // Copyright 2021 the vue-authorized authors. All rights reserved. MIT license.
2 |
3 | import { reactive } from 'vue'
4 | import { IReactive } from './type'
5 |
6 | export const permssions = reactive({
7 | value: [],
8 |
9 | // 优先验证 hasPermission,如果为 false 则无权限
10 | // 因为 value 可能会异步加载,初始化为空无法准确判断
11 | hasPermission: true
12 | })
13 |
14 | export const persMap = new Map()
15 |
--------------------------------------------------------------------------------
/src/Authorized/index.ts:
--------------------------------------------------------------------------------
1 | // Copyright 2021 the vue-authorized authors. All rights reserved. MIT license.
2 |
3 | import Authorized from './Authorized.vue'
4 | import { handleSetPermissions, checkedPermission } from './utils'
5 |
6 | Authorized.setPermissions = handleSetPermissions
7 | Authorized.checked = checkedPermission
8 |
9 | export const setPermissions = handleSetPermissions
10 | export const checked = checkedPermission
11 |
12 | export default Authorized
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 | on:
3 | push:
4 | branches:
5 | - main
6 | jobs:
7 | test:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout
11 | uses: actions/checkout@v2
12 | with:
13 | persist-credentials: false
14 | - name: Install
15 | uses: sergioramos/yarn-actions/install@v6
16 | with:
17 | frozen-lockfile: true
18 | - name: Unit test
19 | run: |
20 | npm run test
--------------------------------------------------------------------------------
/scripts/release.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 |
4 | function resolve(_path) {
5 | return path.join(__dirname, '..', _path)
6 | }
7 |
8 | fs.unlinkSync(resolve('./dist/demo.html'))
9 | fs.copyFileSync(resolve('package.json'), resolve('./dist/package.json'))
10 | fs.copyFileSync(resolve('README.md'), resolve('./dist/README.md'))
11 | fs.copyFileSync(resolve('yarn.lock'), resolve('./dist/yarn.lock'))
12 | fs.copyFileSync(resolve('LICENSE'), resolve('./dist/LICENSE'))
13 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "importHelpers": true,
8 | "moduleResolution": "node",
9 | "skipLibCheck": true,
10 | "esModuleInterop": true,
11 | "allowSyntheticDefaultImports": true,
12 | "sourceMap": true,
13 | "baseUrl": ".",
14 | "types": [
15 | "webpack-env"
16 | ],
17 | "paths": {
18 | "@/*": [
19 | "src/*"
20 | ]
21 | },
22 | "lib": [
23 | "esnext",
24 | "dom",
25 | "dom.iterable",
26 | "scripthost"
27 | ]
28 | },
29 | "include": [
30 | "src/**/*.ts",
31 | "src/**/*.tsx",
32 | "src/**/*.vue",
33 | "tests/**/*.ts",
34 | "tests/**/*.tsx"
35 | ],
36 | "exclude": [
37 | "node_modules"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | globals: {
3 | // work around: https://github.com/kulshekhar/ts-jest/issues/748#issuecomment-423528659
4 | 'ts-jest': {
5 | diagnostics: {
6 | ignoreCodes: [151001],
7 | },
8 | },
9 | },
10 | testEnvironment: 'jsdom',
11 | transform: {
12 | '^.+\\.vue$': 'vue-jest',
13 | '^.+\\.(t|j)sx?$': [
14 | 'babel-jest', {
15 | presets: [
16 | [
17 | '@babel/preset-env',
18 | {
19 | targets: {
20 | node: true,
21 | },
22 | },
23 | ],
24 | '@babel/preset-typescript',
25 | ],
26 | plugins: [
27 | '@vue/babel-plugin-jsx',
28 | '@babel/plugin-proposal-class-properties',
29 | ],
30 | },
31 | ],
32 | },
33 | moduleFileExtensions: ['ts', 'tsx', 'js', 'json', 'vue'],
34 | // u can change this option to a more specific folder for test single component or util when dev
35 | // for example, ['/packages/input']
36 | roots: [''],
37 | }
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 xiejiahe
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-authorized",
3 | "version": "1.1.1",
4 | "description": "Vue authorized",
5 | "main": "./Authorized.common.js",
6 | "homepage": "https://github.com/xjh22222228/vue-authorized",
7 | "bugs": {
8 | "url": "https://github.com/xjh22222228/vue-authorized/issues"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/xjh22222228/vue-authorized.git"
13 | },
14 | "keywords": [
15 | "authorized",
16 | "vue-authorized",
17 | "ABAC"
18 | ],
19 | "scripts": {
20 | "start": "npm run serve",
21 | "serve": "vue-cli-service serve",
22 | "build": "vue-cli-service build --target lib --dest dist --name Authorized 'src/Authorized/index.ts'",
23 | "test": "jest __tests__",
24 | "release": "node scripts/release.js"
25 | },
26 | "devDependencies": {
27 | "@babel/plugin-proposal-class-properties": "^7.14.5",
28 | "@babel/preset-env": "^7.14.7",
29 | "@babel/preset-typescript": "^7.14.5",
30 | "@types/jest": "^26.0.24",
31 | "@vue/babel-plugin-jsx": "^1.0.6",
32 | "@vue/cli-plugin-typescript": "~4.5.13",
33 | "@vue/cli-service": "~4.5.13",
34 | "@vue/compiler-sfc": "^3.1.4",
35 | "@vue/test-utils": "^2.0.0-rc.10",
36 | "babel-jest": "^26.3.0",
37 | "jest": "^26.6.3",
38 | "ts-jest": "^26.4.4",
39 | "typescript": "~3.9.3",
40 | "vue": "^3.1.4",
41 | "vue-authorized": "^1.1.1",
42 | "vue-jest": "^5.0.0-alpha.10",
43 | "vue-template-compiler": "^2.6.14"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | no-match
9 |
10 |
11 |
12 |
13 |
14 |
15 | production:
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
59 |
60 |
70 |
--------------------------------------------------------------------------------
/src/Authorized/Authorized.vue:
--------------------------------------------------------------------------------
1 | // Copyright 2021 the vue-authorized authors. All rights reserved. MIT license.
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
60 |
--------------------------------------------------------------------------------
/src/Authorized/utils.ts:
--------------------------------------------------------------------------------
1 | // Copyright 2021 the vue-authorized authors. All rights reserved. MIT license.
2 |
3 | import { permssions, persMap } from './reactive'
4 | import { IAuthority } from './type'
5 |
6 | // 没有权限则传入 null
7 | export function handleSetPermissions(pers: unknown[] | null) {
8 | // No permissions
9 | if (
10 | pers === null ||
11 | (Array.isArray(pers) && pers.length === 0)
12 | ) {
13 | permssions.hasPermission = false
14 | persMap.clear()
15 | return
16 | }
17 |
18 | if (!Array.isArray(pers)) {
19 | return
20 | }
21 |
22 | persMap.clear()
23 | for (let i = 0; i < pers.length; i++) {
24 | persMap.set(pers[i], true)
25 | }
26 |
27 | if (pers.length > 0) {
28 | permssions.hasPermission = true
29 | }
30 |
31 | permssions.value = pers
32 | }
33 |
34 | // Check permissions
35 | // Return target
36 | export function checkedPermission(
37 | authority: IAuthority,
38 | target = true,
39 | ): any {
40 |
41 | if (target === undefined) {
42 | target = true
43 | }
44 |
45 | // falsy: No permissions specified
46 | if (!authority) {
47 | return target
48 | }
49 |
50 | if (
51 | typeof authority === 'string' ||
52 | typeof authority === 'boolean' ||
53 | typeof authority === 'number' ||
54 | // null|undefined
55 | authority == null
56 | ) {
57 | if (persMap.has(authority)) {
58 | return target
59 | }
60 |
61 | return false
62 | }
63 |
64 | if (Array.isArray(authority)) {
65 | for (let i = 0; i < authority.length; i++) {
66 | if (persMap.has(authority[i])) {
67 | return target
68 | }
69 | }
70 |
71 | return false
72 | }
73 |
74 |
75 | throw new Error('[vue-authorized]: unsupported parameters')
76 | }
77 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
用于Vue3, 基于 ABAC 权限验证
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | ## 安装
14 | ```bash
15 | npm i vue-authorized -S
16 | # or
17 | yarn add vue-authorized
18 | ```
19 |
20 |
21 | ## 使用
22 | 一个典型的例子:
23 |
24 | `authority` 参数接收 `string`/`Array`/`number`/`boolean` , 如果是数组则有任意一个匹配则验证通过
25 | ```vue
26 |
27 |
30 | 有权限则显示
31 |
32 |
33 |
34 |
54 | ```
55 |
56 |
57 | 通过 API `Authorized.checked` 验证权限
58 | ```vue
59 |
60 | 有权限则显示
61 |
62 |
63 |
84 | ```
85 |
86 |
87 | 接收插槽 `no-match` 没有权限的情况下显示内容:
88 | ```vue
89 |
90 |
93 | 有权限则显示
94 |
95 |
96 | 无权限
97 |
98 |
99 |
100 | ```
101 |
102 |
103 | 无权限传入 `null` 或 空数组
104 | ```vue
105 |