{"id":23042285,"url":"https://github.com/janyork/node-auth","last_synced_at":"2025-08-14T21:32:27.247Z","repository":{"id":264845140,"uuid":"894454393","full_name":"JanYork/node-auth","owner":"JanYork","description":"NodeJS's permission management framework.","archived":false,"fork":false,"pushed_at":"2024-11-26T12:14:10.000Z","size":0,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"dev","last_synced_at":"2024-11-26T12:32:42.286Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JanYork.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-26T11:38:39.000Z","updated_at":"2024-11-26T12:14:14.000Z","dependencies_parsed_at":"2024-11-26T12:43:28.243Z","dependency_job_id":null,"html_url":"https://github.com/JanYork/node-auth","commit_stats":null,"previous_names":["janyork/node-auth"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JanYork%2Fnode-auth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JanYork%2Fnode-auth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JanYork%2Fnode-auth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JanYork%2Fnode-auth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JanYork","download_url":"https://codeload.github.com/JanYork/node-auth/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229871062,"owners_count":18137134,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-15T20:23:59.346Z","updated_at":"2024-12-15T20:24:00.471Z","avatar_url":"https://github.com/JanYork.png","language":"TypeScript","readme":"## NAUTH\n\nNAUTH is a Node.js authentication and permission management framework. It is designed to be simple to use and easy to integrate into any Node.js application.\n\n\u003e Node.js 认证与权限管理框架\n\n### Quick to use\n\n```shell\nnpm install @i-xor/nauth\n\npnpm install @i-xor/nauth\n\nyarn add @i-xor/nauth\n```\n\n```ts\nimport { NauthManager } from './manager';\nimport { NauthConfiguration } from './configuration';\n\nNauthManager.setConfiguration(new NauthConfiguration());\nNauthManager.setDB(adapter);\n\n// Check nauth whether it's ready.\nNauthManager.check()\n```\n\n```ts\nVerifier.login(uid);\n```\n\n### Configuration\n\n\u003e You can directly create configuration objects, and they have default values.\n\n```ts\nconst configuration = new NauthConfiguration();\n\n// Please refer to it for details.\nexport class NauthConfiguration {\n  constructor(config?: Partial\u003cNauthConfiguration\u003e) {\n    if (config) {\n      Object.assign(this, config);\n    }\n  }\n\n  /**\n   * Token 名称\n   */\n  public readonly tokenName: string = 'token';\n\n  /**\n   * Token 有效时长 (单位s)\n   */\n  public readonly tokenTimeout = 3 * 24 * 60 * 60;\n\n  /**\n   * Token 样式 (UUID | SIMPLE_UUID | NANO_ID | RANDOM_STR)\n   */\n  public readonly tokenStyle:\n    | 'UUID'\n    | 'SIMPLE_UUID'\n    | 'NANO_ID'\n    | 'RANDOM_STR' = 'UUID';\n\n  /**\n   * Token 前缀\n   */\n  public readonly tokenPrefix: string = 'Bearer ';\n\n  /**\n   * Token 续签时长 (单位s)，在过期时间内续签\n   */\n  public readonly tokenRenew = 24 * 60 * 60;\n\n  /**\n   * Token 续签条件 (单位s)，在距离过期时间小于该值时触发续签\n   */\n  public readonly tokenRenewCondition = 12 * 60 * 60;\n}\n```\n\n\u003e There are a few properties that you can set.\n\n```ts\nconst configuration = new NauthConfiguration({\n  tokenName: 'token',\n  tokenTimeout: 3 * 24 * 60 * 60,\n})\n```\n\n### Test\n\n```shell\nnpm run test\nnpm run test:coverage\n\npnpm run test \npnpm run test:coverage\n\nyarn test\nyarn test:coverage\n```\n\n### Login\n\n```ts\nconst _token = await checkPass(username, password) ? await Verifier.login(username) : null;\n\nconst id = await Verifier.loginID(_token);\n\nconst token = await Verifier.tokenValue(id);\n\nconst user = await Verifier.info(id);\n\nconst ctx = await Verifier.ctx(id);\n\nconst isLogin = await Verifier.isLogin(id);\n\nawait Verifier.logout(id);\n```\n\n### Router\n    \n```ts\nRouterMatcher.isMatched('/user/1', '/user/{*path}') ? Verifier.checkLogin(id) : null;\n\nconst router = new RouterMatcher();\nrouter.add('/user/:id', async () =\u003e {\n    const id = ctx.params.id;\n    await Verifier.checkLogin(id);\n});\nrouter.add('/admin/:id', async () =\u003e {\n    const id = ctx.params.id;\n    await Verifier.checkPermission(id, 'user');\n});\nrouter.match('/user/1');\n```\n\n### Manager\n\n```ts\nconst configuration = NauthManager.configuration;\n\nconst db = NauthManager.dbAdapter;\n\nconst verifierLogic = NauthManager.getLogic(logicType);\n```\n### Multiple types of users\n\n#### Create a new class and extend the Verifier class\n```ts\n// Create a new file: user-verifier.ts\n\nimport { Verifier, VerifierLogic } from '@i-xor/nauth';\n\nexport class UserVerifier extends Verifier {\n  static readonly TYPE: string = 'user';\n\n  static _logic: VerifierLogic;\n\n  static set logic(value: VerifierLogic) {\n    this._logic = value;\n  }\n\n  static get logic() {\n    if (!this._logic) {\n      this._logic = new VerifierLogic(this.TYPE);\n    }\n    return this._logic;\n  }\n\n  static init() {\n    this.logic = new VerifierLogic(this.TYPE);\n  }\n}\n\n// Create a new file: admin-verifier.ts\nexport class AdminVerifier extends Verifier {\n  static readonly TYPE: string = 'admin';\n\n  static _logic: VerifierLogic;\n\n  static set logic(value: VerifierLogic) {\n    this._logic = value;\n  }\n\n  static get logic() {\n    if (!this._logic) {\n      this._logic = new VerifierLogic(this.TYPE);\n    }\n    return this._logic;\n  }\n\n  static init() {\n    this.logic = new VerifierLogic(this.TYPE);\n  }\n}\n```\n\n#### Use the new class in the application\n\n```ts\nimport { UserVerifier } from './user-verifier';\nimport { AdminVerifier } from './admin-verifier';\n\nUserVerifier.login(uid);\nAdminVerifier.login(uid);\n```\n\n\u003e There are no changes to the way it is used.\n\n### Long-term validity\n\n\u003e If you want a user's 'token' to be valid for a long time (never expire), you can use this method.\n\n```ts\nVerifier.login(uid);\n\nVerifier.setLongTermValid(uid)\n```\n\n\u003e You can cancel the long-term validity and restore the expiration time.\n\n```ts\nVerifier.removeLongTermValid(uid)\n```\n\n### Customize storage policies\n\nYou need to ensure that the atomicity of the method is mutually exclusive with the consistency in the case of concurrency, otherwise problems may occur !\n\n\u003e Create a new class and extend the DBAdapter class.\n\n```ts\n// Create a new file: mysql-adapter.ts\nexport class MySQLAdapter extends DBAdapter {\n  // Implement the methods in the DBAdapter class\n}\n```\n\n\u003e Use the new class in the application\n\n```ts\nimport { MySQLAdapter } from './mysql-adapter';\n\nNauthManager.setDB(new MySQLAdapter());\n```\n\n\u003e You can also choose to set up a separate authenticator.\n\n```ts\nimport { MySQLAdapter } from './mysql-adapter';\n\nVerifier.setDB(mySQLAdapter);\n```\n\n### Error codes\n\n\u003e You can find out the cause of the error by judging the error code.\n\n\u003e For more error codes, please refer to the definition of the corresponding enumeration class.\n\n#### Not login\n\n```ts\nimport { NotLoginException } from './not-login.exception';\nimport { AUTH_CODE } from './auth-code.constant';\n\ntry {\n  await Verifier.checkLogin(id);\n} catch (error: NotLoginException | MutexException) {\n  if (error instanceof NotLoginException) {\n    switch (error.code) {\n      case AUTH_CODE.NOT_LOGIN:\n        // Do something\n        break;\n      case AUTH_CODE.LOGIN_EXPIRED:\n        // Do something\n        break;\n      default:\n        break;\n    }\n  }\n}\n```\n\n#### Mutex lock\n\n\u003e If you don't want to see this error, please do a good job at the API gateway level: the same user cannot log in, log out, or modify status/information at the same time!\n\u003e \n\u003e 出现MutexException是正常的现象，因为用户的登录和退出以及修改都应当是互斥的，如果你不想见到这个错误，请在API网关层面做好约束：同一个用户不能同时登录、退出登录、修改状态/信息！\n\n```ts\nimport { NotLoginException } from './not-login.exception';\nimport { AUTH_CODE } from './auth-code.constant';\nimport { MUTEX_CODE } from './mutex-code.constant';\n\ntry {\n  await Verifier.checkLogin(id);\n} catch (error: NotLoginException | MutexException) {\n  if (error instanceof MutexException) {\n    switch (error.code) {\n      case MUTEX_CODE.SYSTEM_MUTEX:\n        // Do something\n        break;\n      case MUTEX_CODE.LOCK_TIMEOUT:\n        // Do something\n        break;\n      default:\n        break;\n    }\n  }\n}\n```\n\n### Listener\n\n\u003e You can listen for events and do something when they occur.\n\nEach logic controller (`Logic` \u0026 `Verifier`) has access to a subject.\n\nThe subject is a `Subject\u003cEvent\u003e` object from the `rxjs` library.\n\n\u003e The type of payload you can print after subscribing to view or consult the source code, only the `login`, `logout`, and `kick out triggers` will pass `UserDO`, and the rest may be `null` or `uid`.\n\n```ts\nimport { Event, EVENT_TYPE } from '@i-xor/nauth';\n\nVerifier.subject.subscribe(async (event: Event) =\u003e {\n  switch (event.type) {\n    case EVENT_TYPE.LOGOUT:\n    case EVENT_TYPE.KICKOUT_FEEDBACK:\n      const payload = event.payload as UserDO;\n      // Do something\n      break;\n    case EVENT_TYPE.OFFLINE_ALL:\n      // payload is null\n      // Do something\n      break;\n  }\n});\n```\n\n```ts\n// You can also use logic to get subject\nconst logic = NauthManager.getLogic(logicType) || Verifier.logic;\n\nlogic.subject.subscribe(async (event: Event) =\u003e {\n  switch (event.type) {\n    case EVENT_TYPE.LOGOUT:\n    case EVENT_TYPE.KICKOUT_FEEDBACK:\n      const payload = event.payload as UserDO;\n      // Do something\n      break;\n    case EVENT_TYPE.OFFLINE_ALL:\n      // payload is null\n      // Do something\n      break;\n  }\n});\n```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjanyork%2Fnode-auth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjanyork%2Fnode-auth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjanyork%2Fnode-auth/lists"}