Cake.js 🍰
Cake.js 是基于Egg.js的扩展框架,主要使用typescript开发。现阶段提供了:
- 更简单的路由注册方式
- 更简单的passport用户鉴权方式
- 依赖注入
TODO
- 依赖注入过程中的检查
- 查询 DB 时的自动缓存
QuickStart
$ mkdir demo && cd demo
$ npm init cake
$ npm i
$ npm run dev
Features
路由
在这里可以使用Action
注解来实现路由注册,直接在方法的上方一行就可以标记路由信息,而不再需要去router.ts中编写路由信息。
以下是一个示例:
import {Controller} from 'egg';
import Action from '../../node_modules/egg-cakejs/lib/blueprint';
export default class TSHomeController extends Controller {
@Action({method: 'get', path: '/'})
public async index() {
this.ctx.body = '你好';
}
}
这个代码仍然像egg.js
原来的约定一样放在app/controller
目录下。
在这里,@Action({method: 'get', path: '/'})
这一行代表当通过GET
方式请求http://127.0.0.1:7001/
时,就会请求到index这个方法上,浏览器上会显示:你好。
鉴权
Cake.js 使用中间件结合 egg-passport 来实现鉴权。以下编写了一个需要用户登录态的Controller:
import {Controller} from 'egg';
import Action from '../../node_modules/egg-cakejs/lib/blueprint';
export default class TSHomeController extends Controller {
@Action({method: 'get', path: '/', loginRequired: true})
public async index() {
const user = this.ctx.currentUser;
this.ctx.body =`你好,${user.name}`;
}
}
这里只在Action
注解中添加了一个信息:loginRequired: true
,这个信息代表请求时是需要携带用户认证信息的,也就是登录态,此时可以直接通过ctx.currentUser
获取到用户信息,没有登录态则会返回 401 状态码,而不是调用index
方法。
如何实现这样的效果呢?
首先需要在app/passport
目录下实现一个鉴权策略,文件名就叫user.ts
,这里只需要query中包含id参数就算携带了用户认证信息,否则认为不是登录态,以下是代码示例:
import {Application} from 'egg';
import {Strategy} from 'passport';
/**
* 一个假的鉴权策略,可以编写其他的策略,来实现用户鉴权
*/
module.exports = (app: Application) => {
return new (class extends Strategy {
async authenticate(req: any, options?: any) {
if (req.query.id) {
this.success({id: req.query.id, name: req.query.name});
} else {
this.fail();
}
}
})();
};
其次需要修改配置文件( config.default.ts 或是其他环境的配置文件),在里面加一条:config.userPassport = ['user'];
。之所以需要这样配置,是因为项目在启动过程中挂载了一个中间件,这个中间件会加载配置的 passport 策略:
import { Application } from 'egg';
/**
* 通过这个中间件将passport挂在每个请求上去
* @param mwOptions
* @param app
* @returns
*/
export default function auth(mwOptions: any, app: Application) {
const defaultPassport = app.config.defaultPassport ?? [ 'fake' ];
const userPassport = app.config.userPassport ?? []; // 普通用户的鉴权策略
const adminPassport = app.config.adminPassport ?? []; // admin用户的鉴权策略
const passports = [... new Set([ ...userPassport, ...adminPassport, ...defaultPassport ])];
const passportOptions = { session: false, failWithError: false, successReturnToOrRedirect: false, successRedirect: false };
const authMethod = (app as any).passport.authenticate(passports, passportOptions);
return authMethod;
}
passport 策略分三种:defaultPassport(兜底的用户认证方案),userPassport(一般用户的认证方案),adminPassport(超级用户认证方案)。
依赖注入
1.0.21 版本开始支持
在 Cake.js 中使用依赖注入只需要一个注解:Inject
。使用此注解时,给它传的值其实就是egg.js中调用service时惯用的ctx.service.xxx.yyy.method()
中的xxx.yyy
这一段。
以下是一个注入 service 的 Controller:
import {Controller} from 'egg';
import { Action } from '../../node_modules/egg-cakejs/lib/action';
import { Inject } from '../../node_modules/egg-cakejs/lib/register';
import TestService from '../service/test';
export default class TSHomeController extends Controller {
@Inject('test')
private testService: TestService;
@Action({method: 'get', path: '/index'})
public async index() {
const data = await this.testService.get(123);
this.ctx.body = `hi, ${data.name}`;
}
}
其中 TestService 只是一个普通的 Service:
import {Service} from 'egg';
export default class TestService extends Service {
async get(id: number) {
return {id, name: this.ctx.app.config.test.key};
}
}