從零搭建 Node.js 企業級 Web 服務器(七):認證登陸

認證登陸過程

認證登陸就是經過第三方受權來鑑別用戶信息的登陸方式,好比:微信掃碼登陸。目前最爲普遍接受的受權標準是 OAuth2.0,基於 OAuth2.0 的認證登陸本質上是 Web 應用在用戶受權下獲取該用戶在第三方應用上的我的信息的過程:html

a79dc066d43e56aadeefd57c4c58f7e8a2d2e4ff.jpg

關於 passport

OAuth2.0 定義了框架但具體實現根據廠商不一樣多少存在差別,而 passport 模塊提供了抹平這種差別的機制,經過接入不一樣的 strategy 對象能夠對接不一樣的第三方登陸。本章將基於上一章已完成的工程 host1-tech/nodejs-server-examples - 06-session 接入 passport 模塊實現 Github 認證登陸。先在工程根目錄安裝 passport 與 passport-githubnode

$ yarn add passport         # 本地安裝 passport
# ...
info Direct dependencies
└─ passport@0.4.1
# ...

$ yarn add passport-github  # 本地安裝 passport-github
# ...
info Direct dependencies
└─ passport-github@1.1.0
# ...

加上 Github 認證登陸

接下來在 Github 上新建 OAuth 應用git

bc617dc8a1f3311e6b96bbee7a553195a647765c.jpg

而後加上 Github 登陸方式:github

// src/middlewares/auth.js
const passport = require('passport');
const { Strategy: GithubStrategy } = require('passport-github');

const GITHUB_STRATEGY_OPTIONS = {
  clientID: 'b8ada004c6d682426cfb',
  clientSecret: '0b13f2ab5651f33f879a535fc2b316c6c731a041',
  callbackURL: 'http://localhost:9000/api/login/github/callback',
};

const githubStrategy = new GithubStrategy(
  GITHUB_STRATEGY_OPTIONS,
  (accessToken, refreshToken, profile, done) => {
    /**
     * 根據 profile 查找或新建 user 信息
     */
    const user = {};
    done(null, user);
  }
);

passport.use(githubStrategy);

passport.serializeUser((user, done) => {
  /**
   * 根據 user 信息獲取 userId
   */
  const userId = '46e5';
  done(null, userId);
});

passport.deserializeUser((userId, done) => {
  /**
   * 根據 userId 獲取 user 信息
   */
  const user = {};
  done(null, user);
});

module.exports = function authMiddleware() {
  return [passport.initialize(), passport.session()];
};

Object.assign(module.exports, { passport });
// src/middlewares/index.js
const { Router } = require('express');
const cookieParser = require('cookie-parser');
const sessionMiddleware = require('./session');
const urlnormalizeMiddleware = require('./urlnormalize');
const loginMiddleware = require('./login');
+const authMiddleware = require('./auth');

const secret = '842d918ced1888c65a650f993077c3d36b8f114d';

module.exports = async function initMiddlewares() {
  const router = Router();
  router.use(urlnormalizeMiddleware());
  router.use(cookieParser(secret));
  router.use(sessionMiddleware(secret));
  router.use(loginMiddleware());
+  router.use(authMiddleware());
  return router;
};
// src/middlewares/login.js
const { parse } = require('url');

module.exports = function loginMiddleware(
  homepagePath = '/',
  loginPath = '/login.html',
  whiteList = {
    '/500.html': ['get'],
    '/api/health': ['get'],
    '/api/login': ['post'],
+    '/api/login/github': ['get'],
+    '/api/login/github/callback': ['get'],
  }
) {
  //...
};
// src/controllers/login.js
const { Router } = require('express');
+const { passport } = require('../middlewares/auth');

class LoginController {
+  homepagePath;
+  loginPath;
+
  async init() {
    const router = Router();
    router.post('/', this.post);
+    router.get(
+      '/github',
+      passport.authenticate('github', { scope: ['read:user'] })
+    );
+    router.get(
+      '/github/callback',
+      passport.authenticate('github', {
+        failureRedirect: this.loginPath,
+      }),
+      this.getGithubCallback
+    );
    return router;
  }

  post = (req, res) => {
    req.session.logined = true;
-    res.redirect('/');
+    res.redirect(this.homepagePath);
  };
+
+  getGithubCallback = (req, res) => {
+    req.session.logined = true;
+    res.redirect(this.homepagePath);
+  };
}

-module.exports = async () => {
+module.exports = async (homepagePath = '/', loginPath = '/login.html') => {
  const c = new LoginController();
+  Object.assign(c, { homepagePath, loginPath });
  return await c.init();
};
<!-- public/login.html -->
<html>
  <head>
    <meta charset="utf-8" />
  </head>
  <body>
    <form method="post" action="/api/login">
      <button type="submit">一鍵登陸</button>
    </form>
+    <a href="/api/login/github"><button>Github 登陸</button></a>
  </body>
</html>

訪問 http://localhost:9000/login.html 便可體驗 Github 認證登陸邏輯:數據庫

25700e2c7f1ba8f99b6b1c7a58de470d075b7919.gif

須要注意因爲 Github 服務器在海外,偶爾會出現網絡不通致使的認證異常,此時只要稍等一段時間再試就能夠了。另外,登陸過的讀者能夠經過清除 Cookie 重置登陸狀態。express

本章源碼

host1-tech/nodejs-server-examples - 07-authenticationsegmentfault

更多閱讀

從零搭建 Node.js 企業級 Web 服務器(零):靜態服務
從零搭建 Node.js 企業級 Web 服務器(一):接口與分層
從零搭建 Node.js 企業級 Web 服務器(二):校驗
從零搭建 Node.js 企業級 Web 服務器(三):中間件
從零搭建 Node.js 企業級 Web 服務器(四):異常處理
從零搭建 Node.js 企業級 Web 服務器(五):數據庫訪問
從零搭建 Node.js 企業級 Web 服務器(六):會話
從零搭建 Node.js 企業級 Web 服務器(七):認證登陸
從零搭建 Node.js 企業級 Web 服務器(八):網絡安全api

相關文章
相關標籤/搜索