egg-message1
v1.0.1
Published
passport plugin for egg, base on passportjs
Downloads
2
Readme
egg-message
egg插件开发,package.json详解
命名规范
- npm 包名以 egg- 开头,且为全小写,例如:egg-xx。比较长的词组用中划线:egg-foo-bar
- 对应的插件名使用小驼峰,小驼峰转换规则以 npm 包名的中划线为准 egg-foo-bar => fooBar
- 对于可以中划线也可以不用的情况,不做强制约定,例如:userservice(egg-userservice) 还是 user-service(egg-user-service) 都可以
package.json 书写规范
只书写我自己不知道的关键字,其他的请自行在package.json中自我查询
eggPlugin:
- {String} name - 插件名(必须配置),具有唯一性,配置依赖关系时会指定依赖插件的 name。
- {Array} dependencies - 当前插件强依赖的插件列表(如果依赖的插件没找到,应用启动失败)
- 【此处注意:不要和package.json本身的dependencies关键字弄混,这个在eggPlugin内的,是依赖的egg插件,egg-xxxx格式的,而外面的是正常普通npm包】
- 比如我们的插件依赖一个叫egg-pwd的插件,那么"dependencies": [ "pwd" ],不需要再去增加 egg-
- {Array} optionalDependencies - 当前插件的可选依赖插件列表(如果依赖的插件未开启,只会 warning,不会影响应用启动)。
- {Array} env - 只有在指定运行环境才能开启,具体有哪些环境可以参考运行环境。此配置是可选的,一般情况下都不需要配置。
{ "name": "egg-rpc", "eggPlugin": { "name": "rpc", // 插件名 "dependencies": [ "registry" ], // 强依赖的插件列表 "optionalDependencies": [ "vip" ], // 可选依赖插件列表 "env": [ "local", "test", "unittest", "prod" ] // 指定运行环境 } }
description:意义与keywords相似,就是对于插件做一个简介,让使用者更明白他是做什么的
在 keywords 里加上 egg、egg-plugin、eggPlugin 等关键字,便于索引【其实就是类似与淘宝对于商品的多个关键词,便于在插件发布后,提高插件的曝光率】【与description差不多意思】
{ "name": "egg-view-nunjucks", "version": "1.0.0", // 你的插件的版本号 "description": "view plugin for egg", "eggPlugin": { "name": "nunjucks", "dep": [ "security" ] }, "keywords": [ "egg", "egg-plugin", "eggPlugin", "egg-plugin-view", "egg-view", "nunjucks" ], }
举例:针对于egg-view-nunjucks, 我们写的几个关键字,egg,egg-plugin,eggPlugin:属于egg框架能用的插件,egg-plugin-view,egg-view,nunjucks告诉我们这个插件与什么有关
发布文件配置(files)
files 字段用于描述我们使用 npm publish 命令后推送到 npm 服务器的文件列表,如果指定文件夹,则文件夹内的所有内容都会包含进来。我们可以查看下载的 antd 的 package.json 的files 字段,内容如下:
"files": [ "dist", "lib", "es" ],
可以看到下载后的 antd 包是下面的目录结构:
- repository: 项目代码存放地方
"repository": { "type": "git", "url": "git+https://github.com/eggjs/egg-passport.git" // git地址 },
- bugs: 项目问题反馈的Url或报告问题的email地址
"bugs": { "email": "[email protected]", // 反馈问题邮箱 "url": "https://github.com/owner/project/issues" // 反馈问题地址 },
- license:开源许可证
压缩响应消息,
Install
暂时内部使用,直接copy。发布后, $ npm i xxx
Usage
enable message plugin
// 发布前
// config/plugin.js
exports.message = {
enable: true,
package: '../../lib/plugin/egg-message',
};
// 发布后
exports.message = {
enable: true,
package: 'egg-message',
};
Using
// config/config.default.js
exports.msgFilter = {
threshold: 1024 // 小于 1k 的响应体不压缩【默认1024】
};
exports.message = {
enable: true, //
client: {
/**
* parameter config https://github.com/node-modules/parameter
*/
validate: {
// enable: true,
convert: true,
validateRoot: true
},
},
/**
* logAli 上传慢查询日志插件配置
*/
aliLog: {
enable: true, // 是否将应用日志发送到远程 阿里云sls
limitTime: 20, // 毫秒, 上传大于此值的日志,
SlowQueryLog: 'slow_query_log', // 慢查询日志上传表名
ErrorLog: 'error_log' // 错误日志上传表名
}
};
Authenticate Requests
Use app.passport.mount(strategy[, options])
, specifying the 'github'
and 'twitter'
strategy, to authenticate requests.
// app/router.js
module.exports = app => {
app.get('/', 'home.index');
// authenticates routers
app.passport.mount('github');
// this is a passport router helper, it's equal to the below codes
//
// const github = app.passport.authenticate('github');
// app.get('/passport/github', github);
// app.get('/passport/github/callback', github);
// custom options.login url and options.successRedirect
app.passport.mount('twitter', {
loginURL: '/account/twitter',
// auth success redirect to /
successRedirect: '/',
});
};
Verify and store user
Use app.passport.verify(async (ctx, user) => {})
hook:
// app.js
module.exports = app => {
app.passport.verify(async (ctx, user) => {
// check user
assert(user.provider, 'user.provider should exists');
assert(user.id, 'user.id should exists');
// find user from database
//
// Authorization Table
// column | desc
// --- | --
// provider | provider name, like github, twitter, facebook, weibo and so on
// uid | provider unique id
// user_id | current application user id
const auth = await ctx.model.Authorization.findOne({
uid: user.id,
provider: user.provider,
});
const existsUser = await ctx.model.User.findOne({ id: auth.user_id });
if (existsUser) {
return existsUser;
}
// call user service to register a new user
const newUser = await ctx.service.user.register(user);
return newUser;
});
};
How to develop an egg-passport-${provider}
plugin
See example: egg-passport-twitter.
- Plugin dependencies on egg-passport to use
app.passport
APIs.
// package.json
{
"eggPlugin": {
"name": "passportTwitter",
"dependencies": [
"passport"
]
},
}
- Define config and set default values
Must use key
and secret
instead of consumerKey|clientID
and consumerSecret|clientSecret
.
// config/config.default.js
exports.passportTwitter: {
key: '',
secret: '',
callbackURL: '/passport/twitter/callback',
};
- Init
Strategy
inapp.js
and format user inverify callback
// app.js
const debug = require('debug')('egg-passport-twitter');
const assert = require('assert');
const Strategy = require('passport-twitter').Strategy;
module.exports = app => {
const config = app.config.passportTwitter;
// must set passReqToCallback to true
config.passReqToCallback = true;
assert(config.key, '[egg-passport-twitter] config.passportTwitter.key required');
assert(config.secret, '[egg-passport-twitter] config.passportTwitter.secret required');
// convert to consumerKey and consumerSecret
config.consumerKey = config.key;
config.consumerSecret = config.secret;
// register twitter strategy into `app.passport`
// must require `req` params
app.passport.use('twitter', new Strategy(config, (req, token, tokenSecret, params, profile, done) => {
// format user
const user = {
provider: 'twitter',
id: profile.id,
name: profile.username,
displayName: profile.displayName,
photo: profile.photos && profile.photos[0] && profile.photos[0].value,
token,
tokenSecret,
params,
profile,
};
debug('%s %s get user: %j', req.method, req.url, user);
// let passport do verify and call verify hook
app.passport.doVerify(req, user, done);
}));
};
- That's all!
APIs
extent application
app.passport.mount(strategy, options)
: Mount the login and the login callback routers to use the givenstrategy
.app.passport.authenticate(strategy, options)
: Create a middleware that will authorize a third-party account using the givenstrategy
name, with optionaloptions
.app.passport.verify(handler)
: Verify authenticated userapp.passport.serializeUser(handler)
: Serialize user before store into sessionapp.passport.deserializeUser(handler)
: Deserialize user after restore from session
extend context
ctx.user
: get the current authenticated userctx.isAuthenticated()
: Test if request is authenticated* ctx.login(user[, options])
: Initiate a login session foruser
.ctx.logout()
: Terminate an existing login session
Unit Tests
This plugin has includes some mock methods to helper you writing unit tests more conveniently.
app.mockUser([user])
: Mock an authenticated user
const mm = require('egg-mock');
describe('mock user demo', () => {
let app;
before(() => {
app = mm.app();
return app.ready();
});
after(() => app.close());
afterEach(mm.restore);
it('should show authenticated user info', () => {
app.mockUser();
return request(app.callback())
.get('/')
.expect(/user name: mock_name/)
.expect(200);
});
});
app.mockUserContext([user])
: Mock a context instance with authenticated user
it('should get authenticated user and call service', async () => {
const ctx = app.mockUserContext();
const result = await ctx.service.findUser({ id: ctx.user.id });
assert(result.user.id === ctx.user.id);
});
Questions & Suggestions
Please open an issue here.