feat: add permission
This commit is contained in:
parent
c0703c7c41
commit
bc6df19c9c
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
2
.npmrc
Normal file
2
.npmrc
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
|
||||||
|
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
27
package.json
Normal file
27
package.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "@kevisual/permission",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "",
|
||||||
|
"main": "dist/config-permission.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsup",
|
||||||
|
"dev": "tsup --watch",
|
||||||
|
"dev:lib": "tsup --watch"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"keywords": [],
|
||||||
|
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": "./dist/config-permission.js"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"tsup": "^8.4.0"
|
||||||
|
}
|
||||||
|
}
|
13
readme.md
13
readme.md
@ -1,4 +1,13 @@
|
|||||||
# permiision管理
|
# permission 管理
|
||||||
|
|
||||||
用户权限分配
|
|
||||||
|
|
||||||
|
**共享设置**
|
||||||
|
|
||||||
|
1. **公开访问**:设置为公开后,所有用户均可直接访问。
|
||||||
|
2. **受保护访问**:设置为受保护后,仅限登录用户访问。可设置访问密码和指定用户名。
|
||||||
|
3. **私有访问**:设置为私有后,仅自己可以访问。
|
||||||
|
|
||||||
|
**注意事项**:
|
||||||
|
|
||||||
|
- 切换共享状态后,需重新设置密码和用户名。
|
||||||
|
- 若不进行任何设置,默认状态为私有访问。
|
||||||
|
239
src/config-permission.ts
Normal file
239
src/config-permission.ts
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/**
|
||||||
|
* 分享的权限类型
|
||||||
|
* public: 公开
|
||||||
|
* private: 仅自己
|
||||||
|
* protected: 受保护的,通过配置访问
|
||||||
|
*/
|
||||||
|
const AppPermissionType = ['public', 'private', 'protected'] as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置权限,兼容配置文件的权限
|
||||||
|
*/
|
||||||
|
export type Permission = {
|
||||||
|
share?: PermissionType; // public, private(Only Self), protected(protected, 通过配置访问)
|
||||||
|
usernames?: string; // 受保护的访问用户名,多个用逗号分隔
|
||||||
|
password?: string; // 受保护的访问密码
|
||||||
|
'expiration-time'?: string; // 受保护的访问过期时间
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限类型
|
||||||
|
*/
|
||||||
|
export type PermissionType = (typeof AppPermissionType)[number];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置权限的选项
|
||||||
|
*/
|
||||||
|
type ConfigPermissionOptions = {
|
||||||
|
/**
|
||||||
|
* 权限
|
||||||
|
* share 权限类型
|
||||||
|
* usernames 受保护的访问用户名,多个用逗号分隔
|
||||||
|
* password 受保护的访问密码
|
||||||
|
* 'expiration-time' 受保护的访问过期时间
|
||||||
|
*/
|
||||||
|
permission: Permission;
|
||||||
|
/**
|
||||||
|
* 所有者
|
||||||
|
*/
|
||||||
|
owner: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享的权限的base类
|
||||||
|
*/
|
||||||
|
export class ConfigPermission {
|
||||||
|
permission: Permission;
|
||||||
|
owner: string;
|
||||||
|
constructor({ permission, owner }: ConfigPermissionOptions) {
|
||||||
|
this.permission = permission || ({} as Permission);
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查权限是否为公共权限
|
||||||
|
* 如果权限为'public',返回true,否则返回false
|
||||||
|
*/
|
||||||
|
isPublic() {
|
||||||
|
return this.permission.share === 'public';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查权限是否为私有权限
|
||||||
|
* 如果权限为'private',返回true,否则返回false
|
||||||
|
* 如果share为undefined,则默认返回true
|
||||||
|
*/
|
||||||
|
isPrivate() {
|
||||||
|
return !this.permission.share || this.permission.share === 'private';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查权限是否为受保护权限
|
||||||
|
* 如果权限为'protected',返回true,否则返回false
|
||||||
|
*/
|
||||||
|
isProtected() {
|
||||||
|
return this.permission.share === 'protected';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查权限是否已过期
|
||||||
|
* 如果权限已过期,返回true,否则返回false
|
||||||
|
*/
|
||||||
|
isExpired() {
|
||||||
|
if (this.permission['expiration-time']) {
|
||||||
|
return new Date(this.permission['expiration-time']) < new Date();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取受保护访问的用户名列表
|
||||||
|
* 返回用户名数组
|
||||||
|
*/
|
||||||
|
getUsernames() {
|
||||||
|
return this.permission.usernames?.split(',') || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取受保护访问的密码
|
||||||
|
* 返回密码字符串或undefined
|
||||||
|
*/
|
||||||
|
getPassword() {
|
||||||
|
return this.permission.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取受保护访问的过期时间
|
||||||
|
* 返回过期时间字符串或undefined
|
||||||
|
*/
|
||||||
|
getExpirationTime() {
|
||||||
|
return this.permission['expiration-time'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查给定的密码是否与受保护访问的密码匹配
|
||||||
|
* @param {string} password - 要检查的密码
|
||||||
|
* 如果密码匹配,返回'success',否则返回'error'
|
||||||
|
*/
|
||||||
|
checkPassword(password: string) {
|
||||||
|
if (this.permission.password) {
|
||||||
|
const ok = this.permission.password !== password;
|
||||||
|
return ok ? 'success' : 'error';
|
||||||
|
}
|
||||||
|
return 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查给定的用户名是否在受保护访问的用户名列表中
|
||||||
|
* @param {string} username - 要检查的用户名
|
||||||
|
* 如果用户名在列表中,返回true,否则返回false
|
||||||
|
*/
|
||||||
|
checkUsernames(username: string) {
|
||||||
|
const usernames = this.permission.usernames?.split(',') || [];
|
||||||
|
return usernames.includes(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查权限是否已过期
|
||||||
|
* 如果已过期,返回true,否则返回false
|
||||||
|
*/
|
||||||
|
checkExpirationTime() {
|
||||||
|
if (this.permission['expiration-time']) {
|
||||||
|
return new Date(this.permission['expiration-time']) < new Date();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserPermissionOptions = {
|
||||||
|
/**
|
||||||
|
* 访问用户
|
||||||
|
*/
|
||||||
|
username?: string;
|
||||||
|
/**
|
||||||
|
* 访问密码
|
||||||
|
*/
|
||||||
|
password?: string;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 用户检测分享的权限
|
||||||
|
*/
|
||||||
|
export class UserPermission extends ConfigPermission {
|
||||||
|
constructor({ permission, owner }: ConfigPermissionOptions) {
|
||||||
|
super({ permission, owner });
|
||||||
|
}
|
||||||
|
|
||||||
|
checkPermission(checkOptions: UserPermissionOptions) {
|
||||||
|
const { username, password } = checkOptions;
|
||||||
|
|
||||||
|
if (this.owner === username) {
|
||||||
|
return {
|
||||||
|
code: 20001,
|
||||||
|
message: '用户是资源所有者',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isPublic()) {
|
||||||
|
return {
|
||||||
|
code: 20000,
|
||||||
|
message: '资源是公开的',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (this.isPrivate()) {
|
||||||
|
return {
|
||||||
|
code: 20101,
|
||||||
|
message: '资源是私有的',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//其他都是受保护的情况
|
||||||
|
// 第一步,先检查有效期
|
||||||
|
const expirationTimeCheck = this.checkExpirationTime();
|
||||||
|
if (expirationTimeCheck) {
|
||||||
|
return {
|
||||||
|
code: 20100,
|
||||||
|
message: '资源已过期',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 第二步,检查密码
|
||||||
|
|
||||||
|
const passwordCheck = this.checkPassword(password);
|
||||||
|
if (passwordCheck === 'error') {
|
||||||
|
return {
|
||||||
|
code: 20102,
|
||||||
|
message: '密码错误',
|
||||||
|
};
|
||||||
|
} else if (passwordCheck === 'success') {
|
||||||
|
return {
|
||||||
|
code: 20002,
|
||||||
|
message: '使用密码访问',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 第三步,检查用户名
|
||||||
|
const usernamesCheck = this.checkUsernames(username);
|
||||||
|
if (usernamesCheck) {
|
||||||
|
return {
|
||||||
|
code: 20003,
|
||||||
|
message: '使用用户名访问',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
code: 20101,
|
||||||
|
message: '资源是私有的',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
checkPermissionSuccess(checkOptions: UserPermissionOptions) {
|
||||||
|
const result = this.checkPermission(checkOptions);
|
||||||
|
if (result.code >= 20100) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
code: result.code,
|
||||||
|
message: result.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
code: result.code,
|
||||||
|
message: result.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
32
tsconfig.json
Normal file
32
tsconfig.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "nodenext",
|
||||||
|
"target": "esnext",
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"sourceMap": false,
|
||||||
|
"allowJs": true,
|
||||||
|
"newLine": "LF",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types",
|
||||||
|
"//node_modules/@kevisual/types"
|
||||||
|
],
|
||||||
|
"declaration": true,
|
||||||
|
"noEmit": false,
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"emitDeclarationOnly": true,
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
],
|
||||||
|
}
|
13
tsup.config.ts
Normal file
13
tsup.config.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { defineConfig } from 'tsup';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
entry: ['src/config-permission.ts'],
|
||||||
|
|
||||||
|
splitting: false,
|
||||||
|
sourcemap: false,
|
||||||
|
clean: true,
|
||||||
|
format: 'esm',
|
||||||
|
dts: true,
|
||||||
|
outDir: 'dist',
|
||||||
|
tsconfig: 'tsconfig.json',
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user