From c6f1454ae83ee676530813c4f7583bd8e5411583 Mon Sep 17 00:00:00 2001 From: chenos Date: Sat, 9 Apr 2022 15:30:43 +0800 Subject: [PATCH] feat: jwt service --- packages/api/src/index.ts | 33 ++++++++++++++-- packages/plugin-users/src/jwt-service.ts | 2 +- .../src/middlewares/parseToken.ts | 38 ++++++++----------- packages/plugin-users/src/server.ts | 6 +-- packages/server/src/helper.ts | 3 ++ 5 files changed, 51 insertions(+), 31 deletions(-) diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index fff87164d..2c721d20e 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -45,18 +45,43 @@ const plugins = [ '@nocobase/plugin-ui-routes-storage', '@nocobase/plugin-file-manager', '@nocobase/plugin-system-settings', - '@nocobase/plugin-users', + [ + '@nocobase/plugin-users', + { + jwt: { + secret: process.env.JWT_SECRET || '09f26e402586e2faa8da4c98a35f1b20d6b033c60', + }, + installing: { + adminNickname: 'Super Admin', + adminEmail: 'admin@nocobase.com', + adminPassword: 'admin123', + }, + }, + ], '@nocobase/plugin-acl', '@nocobase/plugin-china-region', '@nocobase/plugin-workflow', + [ + '@nocobase/plugin-client', + { + dist: resolve(__dirname, '../../app/dist'), + }, + ], ]; for (const plugin of plugins) { - api.plugin(require(plugin).default); + if (Array.isArray(plugin)) { + api.plugin(require(plugin.shift() as string).default, plugin.shift()); + } else { + api.plugin(require(plugin).default); + } } -api.plugin(require('@nocobase/plugin-client').default, { - dist: resolve(__dirname, '../../app/dist'), +api.acl.use(async (ctx, next) => { + ctx.permission = { + skip: true, + }; + await next(); }); if (process.argv.length < 3) { diff --git a/packages/plugin-users/src/jwt-service.ts b/packages/plugin-users/src/jwt-service.ts index 0dd34b33c..e18c7a838 100644 --- a/packages/plugin-users/src/jwt-service.ts +++ b/packages/plugin-users/src/jwt-service.ts @@ -1,4 +1,4 @@ -import * as jwt from 'jsonwebtoken'; +import jwt from 'jsonwebtoken'; export interface JwtOptions { secret: string; diff --git a/packages/plugin-users/src/middlewares/parseToken.ts b/packages/plugin-users/src/middlewares/parseToken.ts index 52bd00d10..fb19d3a42 100644 --- a/packages/plugin-users/src/middlewares/parseToken.ts +++ b/packages/plugin-users/src/middlewares/parseToken.ts @@ -1,14 +1,9 @@ import { Context, Next } from '@nocobase/actions'; import UsersPlugin from '../server'; -// TODO(feature): 表名应在 options 中配置 -// 中间件默认只解决解析 token 和附加对应 user 的工作,不解决是否提前报 401 退出。 - -// 因为是否提供匿名访问资源是应用决定的,不是使用插件就一定不能匿名访问。 -export function parseToken(options?: any) { +export function parseToken(options?: { plugin: UsersPlugin }) { return async function parseToken(ctx: Context, next: Next) { - const user = await findUserByToken(ctx); - + const user = await findUserByToken(ctx, options.plugin); if (user) { ctx.state.currentUser = user; setCurrentRole(ctx, user); @@ -33,24 +28,21 @@ function setCurrentRole(ctx, user) { } } -async function findUserByToken(ctx: Context) { - const token = getTokenFromCtx(ctx); +async function findUserByToken(ctx: Context, plugin: UsersPlugin) { + const token = ctx.getBearerToken(); if (!token) { return null; } + try { + const { userId } = await plugin.jwtService.decode(token); - const pluginUser = ctx.app.getPlugin('@nocobase/plugin-users'); - - const { userId } = await pluginUser.jwtService.decode(token); - - return await ctx.db.getRepository('users').findOne({ - filter: { - id: userId, - }, - appends: ['roles'], - }); -} - -function getTokenFromCtx(ctx: Context) { - return ctx.get('Authorization').replace(/^Bearer\s+/gi, ''); + return await ctx.db.getRepository('users').findOne({ + filter: { + id: userId, + }, + appends: ['roles'], + }); + } catch (error) { + console.warn(error); + } } diff --git a/packages/plugin-users/src/server.ts b/packages/plugin-users/src/server.ts index a98846c40..2869eea7a 100644 --- a/packages/plugin-users/src/server.ts +++ b/packages/plugin-users/src/server.ts @@ -2,8 +2,8 @@ import { Collection } from '@nocobase/database'; import { Plugin } from '@nocobase/server'; import { resolve } from 'path'; import * as actions from './actions/users'; -import * as middlewares from './middlewares'; import { JwtOptions, JwtService } from './jwt-service'; +import * as middlewares from './middlewares'; export interface UserPluginConfig { jwt: JwtOptions; @@ -76,7 +76,7 @@ export default class UsersPlugin extends Plugin { this.app.resourcer.registerActionHandler(`users:${key}`, action); } - this.app.resourcer.use(middlewares.parseToken()); + this.app.resourcer.use(middlewares.parseToken({ plugin: this })); const publicActions = ['check', 'signin', 'signup', 'lostpassword', 'resetpassword', 'getUserByResetToken']; const loggedInActions = ['signout', 'updateProfile', 'changePassword', 'setDefaultRole']; @@ -100,7 +100,7 @@ export default class UsersPlugin extends Plugin { adminNickname = 'Super Admin', adminEmail = 'admin@nocobase.com', adminPassword = 'admin123', - } = this.options.installing; + } = this.options.installing || {}; return { adminNickname, diff --git a/packages/server/src/helper.ts b/packages/server/src/helper.ts index b026e2244..510566e9d 100644 --- a/packages/server/src/helper.ts +++ b/packages/server/src/helper.ts @@ -110,6 +110,9 @@ export function registerMiddlewares(app: Application, options: ApplicationOption ); app.use(async (ctx, next) => { + ctx.getBearerToken = () => { + return ctx.get('Authorization').replace(/^Bearer\s+/gi, ''); + }; ctx.db = app.db; ctx.resourcer = app.resourcer; const i18n = app.i18n.cloneInstance({ initImmediate: false });