Skip to content

Commit

Permalink
docs(passport): translation for passport tutorial (#2235)
Browse files Browse the repository at this point in the history
  • Loading branch information
cemremengu authored and popomore committed Apr 13, 2018
1 parent 6fad4e1 commit ee2d2b3
Show file tree
Hide file tree
Showing 2 changed files with 285 additions and 3 deletions.
284 changes: 283 additions & 1 deletion docs/source/en/tutorials/passport.md
Original file line number Diff line number Diff line change
@@ -1 +1,283 @@
this document is still waiting for translation, see [Chinese Version](/zh-cn/tutorials/passport.html)
## Title: Passport

**`Login authentication`** is a common business scenario, including "account password login" and "third-party unified login".

Among them, we often use the latter, such as Google, GitHub, QQ unified login, which are based on [OAuth](https://oauth.net/2/) specification.

[Passport](http://www.passportjs.org/) is a highly scalable authentication middleware that supports the `Strategy` of `Github` ,`Twitter`,`Facebook`, and other well-known service vendors. It also supports login authorization verification via account passwords.

Egg provides an [egg-passport](https://github.com/eggjs/egg-passport) plugin which encapsulates general logic such as callback processing after initialization and the success of authentication so that the developers can use Passport with just a few API calls.

The execution sequence of [Passport](http://www.passportjs.org/) is as follows:

* User accesses page
* Check Session
* Intercept and jump to authentication login page
* Strategy Authentication
* Check and store user information
* Serialize user information to Session
* Jump to the specified page

## Using egg-passport

Below, we will use GitHub login as an example to demonstrate how to use it.

### Installation

```bash
$ npm i --save egg-passport
$ npm i --save egg-passport-github
```

For more plugins, see [GitHub Topic - egg-passport](https://github.com/topics/egg-passport) .

### Configuration

**Enabling the plugin:**

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

module.exports.passportGithub = {
enable: true,
package: 'egg-passport-github'
};
```

**Configuration:**

Note: The [egg-passport](https://github.com/eggjs/egg-passport) standardizes the configuration fields, which are unified as `key` and `secret`.

```js
// config/default.js
config.passportGithub = {
key: 'your_clientID',
secret: 'your_clientSecret'
};
```

**note:**

* Create a [GitHub OAuth Apps](https://github.com/settings/applications/new) to get the `clientID` and `clientSecret` information.
* Specify a `callbackURL`, such as `http://127.0.0.1:7001/passport/github/callback`
  - You need to update to the corresponding domain name when deploying online
  - The path is configured via `options.callbackURL`, which defaults to `/passport/${strategy}/callback`

### Mounting Routes

```js
// app/router.js
module.exports = app => {
  const { router, controller } = app;

  // Mount the authentication route
  app.passport.mount('github');

  // The mount above is syntactic sugar, which is equivalent to
  // const github = app.passport.authenticate('github', {});
  // router.get('/passport/github', github);
  // router.get('/passport/github/callback', github);
}
```

### User Information Processing

Then we also need:

* When signing in for the first time, you generally need to put user information into the repository and record the Session.
* In the second login, the user information obtained from OAuth or Session, and the database is read to get the complete user information.

```js
// 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 information from the 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 service to register a new user
    const newUser = await ctx.service.user.register(user);
    return newUser;
  });

  // Serialize and store the user information into session. Generally, only a few fields need to be streamlined/saved.
  app.passport.serializeUser(async (ctx, user) => {
  // process user
  // ...
  // return user;
  });

  // Deserialize the user information from the session, check the database to get the complete information
  app.passport.deserializeUser(async (ctx, user) => {
  // process user
  // ...
  // return user;
  });
};
```

At this point, we have completed all the configurations. For a complete example, see: [eggjs/examples/passport](https://github.com/eggjs/examples/tree/master/passport)

### API

[egg-passport](https://github.com/eggjs/egg-passport) provides the following extensions:

* `ctx.user` - Get current logged in user information
* `ctx.isAuthenticated()` - Check if the request is authorized
* `ctx.login(user, [options])` - Start a login session for the user
* `ctx.logout()` - Exit and clear user information from session
* `ctx.session.returnTo=` - Set redirect address after authentication page success

The API also be provided for:

* `app.passport.verify(async (ctx, user) => {})` - Check user
* `app.passport.serializeUser(async (ctx, user) => {})` - Serialize user information into session
* `app.passport.deserializeUser(async (ctx, user) => {})` - Deserialize user information from the session
* `app.passport.authenticate(strategy, options)` - Generate the specified authentication middleware
  - `options.successRedirect` - specifies the redirect address after successful authentication
  - `options.loginURL` - jump login address, defaults to `/passport/${strategy}`
  - `options.callbackURL` - callback address after authorization, defaults to `/passport/${strategy}/callback`
* `app.passport.mount(strategy, options)` - Syntactic sugar for developers to configure routing

## Using Passport Ecosystem

[Passport](http://www.passportjs.org/) has many middleware and it is impossible to have the second encapsulation.
Next, let's look at how to use Passport middleware directly in the framework.
We will use [passport-local](https://github.com/jaredhanson/passport-local) for "account password login" as an example:

### Installation

```bash
$ npm i --save passport-local
```

### Configuration

```js
// app.js
const LocalStrategy = require('passport-local').Strategy;

module.exports = app => {
  // Mount strategy
  app.passport.use(new LocalStrategy({
    passReqToCallback: true,
  }, (req, username, password, done) => {
    // format user
    const user = {
      provider: 'local',
      username,
      password,
    };
    debug('%s %s get user: %j', req.method, req.url, user);
    app.passport.doVerify(req, user, done);
  }));

  // Process user information
  app.passport.verify(async (ctx, user) => {});
  app.passport.serializeUser(async (ctx, user) => {});
  app.passport.deserializeUser(async (ctx, user) => {});
};
```

### Mounting Routes

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

  // Callback page after successful authentication
  router.get('/authCallback', controller.home.authCallback);

  // Render login page, user inputs account password
  router.get('/login', controller.home.login);
  // Login verification
  router.post('/login', app.passport.authenticate('local', { successRedirect: '/authCallback' }));
};
```

## How to develop an egg-passport plugin

In the previous section, we learned how to use a Passport middleware in the framework. We can further encapsulate it as a plugin and give back to the community.

**initialization:**

```bash
$ egg-init --type=plugin egg-passport-local
```

**Configure dependencies in `package.json`:**

```json
{
"name": "egg-passport-local",
"version": "1.0.0",
"eggPlugin": {
"name": "passportLocal",
"dependencies": ["passport"]
},
"dependencies": {
"passport-local": "^1.0.0"
}
}
```

**Configuration:**

```js
// {plugin_root}/config/config.default.js
// https://github.com/jaredhanson/passport-local
exports.passportLocal = {
};
```

Note: [egg-passport](https://github.com/eggjs/egg-passport) standardizes the configuration fields, which are unified as `key` and `secret`, so if the corresponding Passport middleware attribute names are inconsistent, the developer should do the conversion.

**Register the passport middleware:**

```js
// {plugin_root}/app.js
const LocalStrategy = require('passport-local').Strategy;

module.exports = app => {
  const config = app.config.passportLocal;
  config.passReqToCallback = true;

  app.passport.use(new LocalStrategy(config, (req, username, password, done) => {
    // Cleans up the data returned by the Passport plugin and returns the User object
    const user = {
      provider: 'local',
      username,
      password,
    };
    // This does not process application-level logic and passes it to app.passport.verify for unified processing.
    app.passport.doVerify(req, user, done);
  }));
};
```

[passport]: http://www.passportjs.org/
[egg-passport]: https://github.com/eggjs/egg-passport
[passport-local]: https://github.com/jaredhanson/passport-local
[eggjs/examples/passport]: https://github.com/eggjs/examples/tree/master/passport
4 changes: 2 additions & 2 deletions docs/source/zh-cn/tutorials/passport.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ $ npm i --save egg-passport-github

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

exports.passportGithub = {
module.exports.passportGithub = {
enable: true,
package: 'egg-passport-github',
};
Expand Down

0 comments on commit ee2d2b3

Please sign in to comment.