feat: jwt service

This commit is contained in:
chenos 2022-04-09 15:30:43 +08:00
parent e8a7e321f0
commit c6f1454ae8
5 changed files with 51 additions and 31 deletions

View File

@ -45,18 +45,43 @@ const plugins = [
'@nocobase/plugin-ui-routes-storage',
'@nocobase/plugin-file-manager',
'@nocobase/plugin-system-settings',
[
'@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) {
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) {

View File

@ -1,4 +1,4 @@
import * as jwt from 'jsonwebtoken';
import jwt from 'jsonwebtoken';
export interface JwtOptions {
secret: string;

View File

@ -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,15 +28,13 @@ 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;
}
const pluginUser = ctx.app.getPlugin('@nocobase/plugin-users');
const { userId } = await pluginUser.jwtService.decode(token);
try {
const { userId } = await plugin.jwtService.decode(token);
return await ctx.db.getRepository('users').findOne({
filter: {
@ -49,8 +42,7 @@ async function findUserByToken(ctx: Context) {
},
appends: ['roles'],
});
}
function getTokenFromCtx(ctx: Context) {
return ctx.get('Authorization').replace(/^Bearer\s+/gi, '');
} catch (error) {
console.warn(error);
}
}

View File

@ -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<UserPluginConfig> {
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<UserPluginConfig> {
adminNickname = 'Super Admin',
adminEmail = 'admin@nocobase.com',
adminPassword = 'admin123',
} = this.options.installing;
} = this.options.installing || {};
return {
adminNickname,

View File

@ -110,6 +110,9 @@ export function registerMiddlewares(app: Application, options: ApplicationOption
);
app.use<DefaultState, DefaultContext>(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 });