使用 Redis 實施的 OAuth 2 - 授予型別密碼

在這個例子中,我將使用 redis 資料庫在 rest api 中使用 oauth2

重要提示: 你需要在你的計算機上安裝 redis 資料庫,從這裡為 Linux 使用者下載並從此處安裝 Windows 版本,我們將使用 redis manager 桌面應用程式,從此處安裝。

現在我們必須將 node.js 伺服器設定為使用 redis 資料庫。

  • 建立伺服器檔案:app.js
    var express = require('express'),
  bodyParser = require('body-parser'),
  oauthserver = require('oauth2-server'); // Would be: 'oauth2-server'

var app = express();

app.use(bodyParser.urlencoded({ extended: true }));

app.use(bodyParser.json());

app.oauth = oauthserver({
  model: require('./routes/Oauth2/model'),
  grants: ['password', 'refresh_token'],
  debug: true
});

// Handle token grant requests
app.all('/oauth/token', app.oauth.grant());

app.get('/secret', app.oauth.authorise(), function (req, res) {
  // Will require a valid access_token
  res.send('Secret area');
});

app.get('/public', function (req, res) {
  // Does not require an access_token
  res.send('Public area');
});

// Error handling
app.use(app.oauth.errorHandler());

app.listen(3000);
  • 在 routes / Oauth2 / model.js 中建立 Oauth2 模型
 var model = module.exports,
  util = require('util'),
  redis = require('redis');

var db = redis.createClient();

var keys = {
  token: 'tokens:%s',
  client: 'clients:%s',
  refreshToken: 'refresh_tokens:%s',
  grantTypes: 'clients:%s:grant_types',
  user: 'users:%s'
};

model.getAccessToken = function (bearerToken, callback) {
  db.hgetall(util.format(keys.token, bearerToken), function (err, token) {
    if (err) return callback(err);

    if (!token) return callback();

    callback(null, {
      accessToken: token.accessToken,
      clientId: token.clientId,
      expires: token.expires ? new Date(token.expires) : null,
      userId: token.userId
    });
  });
};

model.getClient = function (clientId, clientSecret, callback) {
  db.hgetall(util.format(keys.client, clientId), function (err, client) {
    if (err) return callback(err);

    if (!client || client.clientSecret !== clientSecret) return callback();

    callback(null, {
      clientId: client.clientId,
      clientSecret: client.clientSecret
    });
  });
};

model.getRefreshToken = function (bearerToken, callback) {
  db.hgetall(util.format(keys.refreshToken, bearerToken), function (err, token) {
    if (err) return callback(err);

    if (!token) return callback();

    callback(null, {
      refreshToken: token.accessToken,
      clientId: token.clientId,
      expires: token.expires ? new Date(token.expires) : null,
      userId: token.userId
    });
  });
};

model.grantTypeAllowed = function (clientId, grantType, callback) {
  db.sismember(util.format(keys.grantTypes, clientId), grantType, callback);
};

model.saveAccessToken = function (accessToken, clientId, expires, user, callback) {
  db.hmset(util.format(keys.token, accessToken), {
    accessToken: accessToken,
    clientId: clientId,
    expires: expires ? expires.toISOString() : null,
    userId: user.id
  }, callback);
};

model.saveRefreshToken = function (refreshToken, clientId, expires, user, callback) {
  db.hmset(util.format(keys.refreshToken, refreshToken), {
    refreshToken: refreshToken,
    clientId: clientId,
    expires: expires ? expires.toISOString() : null,
    userId: user.id
  }, callback);
};

model.getUser = function (username, password, callback) {
  db.hgetall(util.format(keys.user, username), function (err, user) {
    if (err) return callback(err);

    if (!user || password !== user.password) return callback();

    callback(null, {
      id: username
    });
  });
};

你只需在計算機上安裝 redis 並執行以下節點檔案

  #! /usr/bin/env node

var db = require('redis').createClient();

db.multi()
  .hmset('users:username', {
    id: 'username',
    username: 'username',
    password: 'password'
  })
  .hmset('clients:client', {
    clientId: 'client', 
    clientSecret: 'secret'
  })//clientId + clientSecret to base 64 will generate Y2xpZW50OnNlY3JldA==
  .sadd('clients:client:grant_types', [
    'password',
    'refresh_token'
  ])
  .exec(function (errs) {
    if (errs) {
      console.error(errs[0].message);
      return process.exit(1);
    }

    console.log('Client and user added successfully');
    process.exit();
  });

注意 :此檔案將為你的前端設定憑據以請求令牌以便你的請求來自

呼叫上述檔案後的示例 redis 資料庫: StackOverflow 文件

請求如下:

呼叫 api 的示例 StackOverflow 文件

標題:

  1. 授權:基本後跟第一次設定 redis 時設定的密碼:

    一個。clientId + secretId 到 base64

  2. 資料格式:

    username:請求令牌的使用者

    密碼:使用者密碼

    grant_type:取決於你想要什麼選項,我選擇 passwod 只需要用 redis 建立使用者名稱和密碼,redis 上的資料如下:

    {
      "access_token":"1d3fe602da12a086ecb2b996fd7b7ae874120c4f",
      "token_type":"bearer", // Will be used to access api + access+token e.g. bearer 1d3fe602da12a086ecb2b996fd7b7ae874120c4f
      "expires_in":3600,
      "refresh_token":"b6ad56e5c9aba63c85d7e21b1514680bbf711450"
    }
    

所以我們需要呼叫我們的 api 並使用我們剛剛建立的訪問令牌獲取一些安全資料,如下所示:

StackOverflow 文件

當令牌過期 api 會丟擲令牌過期的錯誤,你無法訪問任何 api 呼叫,見下圖:

StackOverflow 文件

讓我們看看如果令牌過期該怎麼辦,讓我先解釋一下,如果訪問令牌過期,redis 中存在一個引用過期 access_token 的 refresh_token 那麼我們需要的是再次使用 refresh_token grant_type 呼叫 oauth / token 並設定授權給 Basic clientId:clientsecret(以 64 位為基礎!)並最終傳送 refresh_token,這將生成一個帶有新到期資料的新 access_token。

下圖顯示瞭如何獲取新的訪問令牌: StackOverflow 文件

希望能幫到你!