Skip to content

Latest commit

 

History

History
227 lines (178 loc) · 8.47 KB

File metadata and controls

227 lines (178 loc) · 8.47 KB

egg-passport-dingtalk

NPM version build status Test coverage David deps Known Vulnerabilities npm download

egg 钉钉的 oauth 登录的插件

依赖说明

依赖的 egg 版本

egg-passport-dingtalk 版本 egg 1.x
1.x 😁
0.x

依赖的插件

$ npm i egg-passport egg-passport-dingtalk --save

开启插件

// {app_root}/config/plugin.js
exports.passport = {
  enable: true,
  package: 'egg-passport'
}

exports.passportDingtalk = {
  enable: true,
  package: 'egg-passport-dingtalk',
};

使用场景

  • 钉钉登录的 oauth 登录插件。

如何本地快速使用?

  1. 先到 https://open-dev.dingtalk.com/#/loginAndShareApp 钉钉开发平台申请 app,如果嫌麻烦可以用下面的配置,后面再申请自己的。

  2. 配置 config/config.default.js

    // {app_root}/config/config.default.js
    exports.passportDingtalk = {
       key: 'dingoajnypqmpu2qrp7wro',
       secret: 'Kb6mm73u0zMyEmUPXzYKnO3TuR9COIgUfsbBc9EhV9VYqVLmUxWGjwE0ojYySFEy',
       // default is /callback/dingtalk
       callbackURL: '/callback/dingtalk',
       // default is /passport/dingtalk
       loginURL: '/passport/dingtalk',
       oauthPageConfig: {
         title: 'your-dingtalk-oauth-page-title',
         logo: 'https://gw.alipayobjects.com/zos/antfincdn/Sr9Hypb7X5/d7b6ba74-f673-476d-9bae-77696aaab106.png',
         slogan: 'your-app-slogan',
       },
        // Your custom dingtalk oauth page, if this is set, the default oauthPageConfig will be invalid
       customLoginURL: null,    
    };
  3. 挂载 passport 的路由

    // app/router.js
    module.exports = app => {
      app.get('/', 'home.index');
    
      // authenticates routers
      app.passport.mount('dingtalk', app.config.passportDingtalk);
      // this is a passport router helper, it's equal to the below codes
      //
      // const dingtalk = app.passport.authenticate('dingtalk');
      // app.get('/passport/dingtalk', dingtalk);
      // app.get('/passport/dingtalk/callback', dingtalk);
    };
  4. 本地启动 egg, 然后访问 http://127.0.0.1:7001/passport/dingtalk。

解决方案

访问的路由必须要登录态

通常,这需要你来写一个中间件来实现。这里先给一个思路,看下面的代码:

// app/router.js
module.exports = app => {
  // 访问 / 前,先有中间件来处理请求
  app.get('/', app.middleware.needLogin(null, app), 'home.index');
  app.passport.mount('dingtalk', app.config.passportDingtalk);
};

关于如何写一个中间请参考这里

// app/middleware/need-login.js
module.exports = (options, app) => {
  return async function needLogin (ctx, next) {
     const passportDingtalkConfig = app.config.passportDingtalk;
     // 如果当前的登录态没有被认证过,则跳转到登录页面
     if (!ctx.isAuthenticated()) {
       return ctx.redirect(passportDingtalkConfig.loginURL);
     }
     await next();   
  }
}

这样实现后,用户访问 '/',会先判断有没有登录,如果没有则跳转到登录页面。

这里只是给出一个最小的例子,当然你可以把这个中间件设置成全局的,然后在扩展一下,设置 ignore path 来全局过滤。

如果来「序列化默认返回用户」或者「用 DB 验证框架返回的用户」

只需要实现一个方法就行:

// app/router.js
module.exports = app => {
  app.get('/', 'home.index');

  // authenticates routers
  app.passport.mount('dingtalk', app.config.passportDingtalk);

  // 用户登录后的第一个回调,这个回调后,会把返回的用户写入 session
  app.passport.verify(async (ctx, user) => {
    // 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;
  });
};

详细配置

请到 config/config.default.js 查看详细配置项说明。

// {app_root}/config/config.default.js
exports.passportDingtalk = {
};
key value note
key string 必须填
secret string 必须填
callbackURL string default is '/callback/dingtalk' 选填,需要与在平台注册的 callback 地址是一个
loginURL string default is '/passport/dingtalk' 选填,默认登录的路由地址
oauthPageConfig.title string 选填,默认登录页的 title
oauthPageConfig.logo string 选填,默认登录页的 logo 地址
oauthPageConfig.slogan string 选填,默认登录页的 slogan
customLoginURL string 选填,如果需要自定义钉钉的登录页面
这个页面就要你自己来负责渲染
具体怎么写可以看一下这个 lib 里的 lib/auth.html 这个例子。
如果设置了这个 oauthPageConfig 这里的配置就无效了。

passport API supported

See https://github.com/eggjs/egg-passport#apis.

extent application

  • app.passport.mount(strategy, options): Mount the login and the login callback routers to use the given strategy.
  • app.passport.authenticate(strategy, options): Create a middleware that will authorize a third-party account using the given strategy name, with optional options.
  • app.passport.verify(handler): Verify authenticated user
  • app.passport.serializeUser(handler): Serialize user before store into session
  • app.passport.deserializeUser(handler): Deserialize user after restore from session

extend context

  • ctx.user: get the current authenticated user
  • ctx.isAuthenticated(): Test if request is authenticated
  • * ctx.login(user[, options]): Initiate a login session for user.
  • ctx.logout(): Terminate an existing login session

提问交流

请到 egg issues 异步交流。

License

MIT