(一)HTTPAuth: Node.js 使用 Koa 的 HTTP BasicAuth 基本認證

要點:html

  • 不要經過 form 提交表單的默認方式發送請求,轉而使用 fetch 或 ajax
  • 客戶端注意設置 Authorization 字段的值爲 'Basic xxx',經過該 Http 字段傳遞用戶名密碼
  • base64 的方法在客戶端要注意兼容性 btoa ,建議使用現成的庫如 'js-base64' 等,NodeJS 方面使用全局的 Buffer
  • 服務端驗證失敗後,注意返回 401,但不用返回 'WWW-Authenticate: Basic realm="..."' 避免瀏覽器出現彈窗
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>AMD</title>
</head>

<body>
  <script defer async="true" src="js/require.js" data-main="js/main"></script>
  <!-- BasicAuth -->
  <div>
    <form id="form" action="">
      <input type="text" name="username" id="username">
      <input type="password" name="password" id="password">
      <button id="login">login</button>
    </form>
  </div>
</body>

</html>
require.config({
  baseUrl: 'js/libs',
  paths: {
    'zepto': 'zepto.min',
  },
  shim: {
    'zepto': 'zepto',
  }
});

define(['zepto'], function ($) {
  let $form = $('#form')
  $form.on('submit', (e) => {
    e.preventDefault()
    $.ajax({
      // ajax 發送驗證請求
      type: 'POST',
      url: '/login',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': 'Basic ' + btoa($('#username').val() + ':' + $('#password').val()),
        // 經過 Authorization 傳遞 base64 編碼後的用戶名密碼
      },
      success: function (data) {
        console.dir(data) // 回調
      }
    })
  })
});
const Koa = require('koa')
const static = require('koa-static')
const router = require('koa-better-router')().loadMethods()
const koaBody = require('koa-body')

const app = new Koa()
app.use(koaBody())
app.use(router.middleware())
app.use(static('public'))
app.listen(8080)

router.post('/login', (ctx, next) => {
  // 省略從數據庫中提取用戶密碼
  if (ctx.get('Authorization') === 'Basic ' + Buffer('fdsa:fdsa').toString('base64')) {
    // 獲取 Authorization 字段 比對 base64 用戶名密碼
    ctx.body = 'secret'
    ctx.type = 'text/html'
    ctx.status = 200 // 匹配成功
  } else {
    ctx.status = 401 // 匹配失敗
  }
  next()
})
相關文章
相關標籤/搜索