feat: add permission

This commit is contained in:
xion 2025-03-22 12:48:22 +08:00
parent c0703c7c41
commit bc6df19c9c
7 changed files with 326 additions and 2 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
dist

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
//registry.npmjs.org/:_authToken=${NPM_TOKEN}

27
package.json Normal file
View 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"
}
}

View File

@ -1,4 +1,13 @@
# permiision管理 # permission 管理
用户权限分配
**共享设置**
1. **公开访问**:设置为公开后,所有用户均可直接访问。
2. **受保护访问**:设置为受保护后,仅限登录用户访问。可设置访问密码和指定用户名。
3. **私有访问**:设置为私有后,仅自己可以访问。
**注意事项**
- 切换共享状态后,需重新设置密码和用户名。
- 若不进行任何设置,默认状态为私有访问。

239
src/config-permission.ts Normal file
View 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'truefalse
*/
isPublic() {
return this.permission.share === 'public';
}
/**
*
* 'private'truefalse
* share为undefinedtrue
*/
isPrivate() {
return !this.permission.share || this.permission.share === 'private';
}
/**
*
* 'protected'truefalse
*/
isProtected() {
return this.permission.share === 'protected';
}
/**
*
* truefalse
*/
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 -
* truefalse
*/
checkUsernames(username: string) {
const usernames = this.permission.usernames?.split(',') || [];
return usernames.includes(username);
}
/**
*
* truefalse
*/
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
View 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
View 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',
});