Rumah  >  Artikel  >  Tutorial CMS  >  Pengesahan berasaskan token dengan Angular dan Node

Pengesahan berasaskan token dengan Angular dan Node

王林
王林asal
2023-09-01 14:01:061265semak imbas

Pengesahan berasaskan token dengan Angular dan Node

Pengesahan ialah salah satu bahagian terpenting dalam mana-mana aplikasi web. Tutorial ini membincangkan sistem pengesahan berasaskan token dan cara ia berbeza daripada sistem log masuk tradisional. Pada penghujung tutorial ini, anda akan melihat demo berfungsi sepenuhnya yang ditulis dalam Angular dan Node.js.

Sistem Pengesahan Tradisional

Sebelum beralih kepada sistem pengesahan berasaskan token, mari kita lihat sistem pengesahan tradisional.

  1. Pengguna menyediakan nama pengguna dan kata laluan dalam borang log masuk dan klik Log masuk.
  2. Selepas membuat permintaan, sahkan pengguna di bahagian belakang dengan menanyakan pangkalan data. Jika permintaan itu sah, sesi dibuat menggunakan maklumat pengguna yang diperoleh daripada pangkalan data dan maklumat sesi dikembalikan dalam pengepala respons supaya ID sesi disimpan dalam penyemak imbas.
  3. Menyediakan maklumat sesi untuk mengakses titik akhir terhad dalam aplikasi anda.
  4. Jika maklumat sesi adalah sah, benarkan pengguna mengakses titik akhir yang ditentukan dan membalas dengan kandungan HTML yang diberikan.

Pengesahan berasaskan token dengan Angular dan Node

Setakat ini bagus. Aplikasi web berfungsi dengan baik dan dapat mengesahkan pengguna supaya mereka boleh mengakses titik akhir terhad. Tetapi apakah yang berlaku apabila anda ingin membangunkan pelanggan lain untuk aplikasi anda (seperti pelanggan Android)? Adakah anda dapat mengesahkan pelanggan mudah alih dan menyediakan kandungan terhad menggunakan aplikasi semasa anda? Seperti yang dinyatakan, tidak. Terdapat dua sebab utama untuk ini:

  1. Sesi dan kuki tidak bermakna untuk aplikasi mudah alih. Anda tidak boleh berkongsi sesi atau kuki yang dibuat di bahagian pelayan dengan pelanggan mudah alih.
  2. Dalam aplikasi semasa, mengembalikan HTML yang diberikan. Dalam pelanggan mudah alih, anda perlu memasukkan sesuatu seperti JSON atau XML sebagai respons.

Dalam kes ini, anda memerlukan aplikasi bebas pelanggan.

Pengesahan berasaskan token

Dalam pengesahan berasaskan token, kuki dan sesi tidak digunakan. Token akan digunakan untuk mengesahkan pengguna untuk setiap permintaan yang dibuat kepada pelayan. Mari kita reka bentuk semula senario pertama menggunakan pengesahan berasaskan token.

Ia akan menggunakan aliran kawalan berikut:

  1. Pengguna menyediakan nama pengguna dan kata laluan dalam borang log masuk dan klik Log masuk.
  2. Selepas membuat permintaan, sahkan pengguna di bahagian belakang dengan membuat pertanyaan dalam pangkalan data. Jika permintaan itu sah, token dibuat menggunakan maklumat pengguna yang diperoleh daripada pangkalan data dan kemudian dikembalikan dalam pengepala respons supaya kami boleh menyimpan penyemak imbas token dalam storan tempatan.
  3. Berikan maklumat token dalam setiap pengepala permintaan untuk mengakses titik akhir terhad dalam aplikasi anda.
  4. Jika token yang diperoleh daripada maklumat pengepala permintaan adalah sah, benarkan pengguna mengakses titik akhir yang ditentukan dan bertindak balas dengan JSON atau XML.

Dalam kes ini, kami tidak memulangkan sesi atau kuki, mahupun sebarang kandungan HTML. Ini bermakna kita boleh menggunakan seni bina ini untuk sebarang aplikasi khusus pelanggan. Anda boleh lihat seni bina seni bina di bawah:

Pengesahan berasaskan token dengan Angular dan Node

Jadi apakah JWT ini?

JWT

JWT bermaksud JSON Web Token dan merupakan format token yang digunakan dalam pengepala kebenaran. Token ini membantu anda mereka bentuk komunikasi antara kedua-dua sistem dengan cara yang selamat. Untuk tujuan tutorial ini, kami akan merumuskan semula JWT sebagai "Token Pembawa". Token pembawa terdiri daripada tiga bahagian: pengepala, muatan dan tandatangan.

  • Header ialah bahagian token yang memegang jenis token dan kaedah penyulitan, yang turut disulitkan menggunakan Base-64.
  • Payloadmengandungi maklumat. Anda boleh memasukkan sebarang jenis data seperti maklumat pengguna, maklumat produk, dsb., yang semuanya disimpan menggunakan penyulitan Base-64.
  • Tandatangan terdiri daripada gabungan pengepala, muatan dan kunci. Kunci mesti disimpan dengan selamat di bahagian pelayan.

Anda boleh lihat skema JWT dan contoh token di bawah:

Pengesahan berasaskan token dengan Angular dan Node

Anda tidak perlu melaksanakan penjana token pembawa kerana anda boleh menemui pakej mantap untuk banyak bahasa. Anda boleh lihat sebahagian daripadanya di bawah:

Node.js https://github.com/auth0/node-jsonwebtoken
PHP http://github.com/firebase/php-jwt
Jawa http://github.com/auth0/java-jwt
红宝石 https://github.com/jwt/ruby-jwt
.BERSIH https://github.com/auth0/java-jwt
Python http://github.com/progrium/pyjwt/

Contoh praktikal

Setelah merangkumi beberapa maklumat asas tentang pengesahan berasaskan token, kini kita boleh beralih kepada contoh praktikal. Lihat seni bina di bawah, kemudian kami akan menganalisisnya dengan lebih terperinci:

Pengesahan berasaskan token dengan Angular dan Node

  1. Berbilang pelanggan (seperti aplikasi web atau pelanggan mudah alih) membuat permintaan kepada API untuk tujuan tertentu.
  2. Permintaan dibuat kepada perkhidmatan seperti https://api.yourexampleapp.com. Jika ramai orang menggunakan aplikasi itu, berbilang pelayan mungkin diperlukan untuk menyediakan operasi yang diminta. https://api.yourexampleapp.com 等服务发出的。如果很多人使用该应用程序,则可能需要多个服务器来提供请求的操作。
  3. 这里,负载均衡器用于平衡请求,以最适合后端的应用程序服务器。当您向 https://api.yourexampleapp.com 发出请求时,负载均衡器首先会处理请求,然后会将客户端重定向到特定服务器。
  4. 有一个应用程序,并且该应用程序部署到多台服务器(server-1、server-2、...、server-n)。每当向 https://api.yourexampleapp.com
  5. Di sini, pengimbang beban digunakan untuk mengimbangi permintaan agar paling sesuai dengan pelayan aplikasi di bahagian belakang. Apabila anda membuat permintaan untuk https://api.yourexampleapp.com, pengimbang beban mula-mula mengendalikan permintaan dan kemudian mengubah hala klien ke pelayan tertentu.

Terdapat aplikasi, dan aplikasi itu digunakan untuk berbilang pelayan (pelayan-1, pelayan-2, ..., pelayan-n). Setiap kali permintaan dibuat kepada https://api.yourexampleapp.com, aplikasi bahagian belakang memintas pengepala permintaan dan mengekstrak maklumat token daripada pengepala Kebenaran. Token ini akan digunakan untuk pertanyaan pangkalan data. Jika token ini sah dan mempunyai kebenaran yang diperlukan untuk mengakses titik akhir yang diminta, ia akan diteruskan. Jika tidak, ia akan mengembalikan kod respons 403 (menunjukkan status terlarang).

Kelebihan

Pengesahan berasaskan token mempunyai pelbagai kelebihan yang menyelesaikan masalah yang serius. Ini antaranya:

Perkhidmatan bebas pelanggan

Dalam pengesahan berasaskan token, token dihantar melalui pengepala permintaan dan bukannya meneruskan maklumat pengesahan dalam sesi atau kuki. Ini bermakna tidak ada negeri. Anda boleh menghantar permintaan kepada pelayan daripada sebarang jenis klien yang boleh membuat permintaan HTTP.

Rangkaian Penghantaran Kandungan (CDN)

Dalam kebanyakan aplikasi web semasa, paparan dipaparkan pada bahagian belakang dan kandungan HTML dikembalikan kepada penyemak imbas. Logik bahagian hadapan bergantung pada kod bahagian belakang.

Tidak perlu mencipta kebergantungan sedemikian. Ini menimbulkan beberapa persoalan. Contohnya, jika anda bekerja dengan agensi reka bentuk yang melaksanakan HTML, CSS dan JavaScript bahagian hadapan, anda perlu memindahkan kod bahagian hadapan itu ke kod hujung belakang supaya beberapa operasi pemaparan atau pengisian boleh berlaku. Selepas beberapa ketika, kandungan HTML yang anda berikan akan sangat berbeza daripada apa yang dilaksanakan oleh agensi kod. Dalam pengesahan berasaskan token, anda boleh membangunkan projek bahagian hadapan anda secara berasingan daripada kod bahagian belakang anda. Kod hujung belakang anda akan mengembalikan respons JSON dan bukannya HTML yang diberikan dan anda boleh meletakkan versi kod bahagian hadapan yang dikecilkan dan digzip ke dalam CDN. Apabila anda melawat halaman web, kandungan HTML akan disampaikan daripada CDN dan kandungan halaman akan diisi oleh perkhidmatan API menggunakan token dalam pengepala Kebenaran.

Sesi tanpa kuki (atau tiada CSRF)🎜 🎜CSRF adalah masalah utama dalam keselamatan rangkaian moden kerana ia tidak menyemak sama ada sumber permintaan itu boleh dipercayai. Untuk menyelesaikan masalah ini, gunakan kumpulan token untuk menghantar token ini pada setiap siaran borang. Dalam pengesahan berasaskan token, token digunakan dalam pengepala kebenaran, dan CSRF tidak mengandungi maklumat ini. 🎜

Storan Token Berterusan

Apabila operasi membaca, menulis atau memadam sesi berlaku dalam aplikasi, ia menjalankan operasi fail dalam folder temp sistem pengendalian, sekurang-kurangnya untuk kali pertama. Katakan anda mempunyai berbilang pelayan dan anda membuat sesi pada pelayan pertama. Apabila anda membuat permintaan lain dan permintaan anda jatuh ke pelayan lain, maklumat sesi tidak akan berada di sana dan anda akan mendapat respons "Tidak Dibenarkan". Saya tahu, anda boleh menyelesaikan masalah ini dengan sesi melekit. Walau bagaimanapun, dalam pengesahan berasaskan token, keadaan ini diselesaikan secara semula jadi. Tiada isu sesi melekit kerana token permintaan dipintas pada setiap permintaan pada mana-mana pelayan. temp 文件夹中进行文件操作,至少第一次是这样。假设您有多个服务器,并且在第一台服务器上创建了一个会话。当您发出另一个请求并且您的请求落入另一台服务器时,会话信息将不存在并且将得到“未经授权”的响应。我知道,你可以通过粘性会话来解决这个问题。然而,在基于令牌的认证中,这种情况自然就解决了。不存在粘性会话问题,因为请求令牌在任何服务器上的每个请求上都会被拦截。

这些是基于令牌的身份验证和通信的最常见优点。关于基于令牌的身份验证的理论和架构讨论就到此结束。是时候看一个实际例子了。

示例应用程序

您将看到两个应用程序来演示基于令牌的身份验证:

  1. 基于令牌的身份验证后端
  2. 基于令牌的身份验证前端

在后端项目中,会有服务的实现,服务结果将是JSON格式。服务中没有返回视图。在前端项目中,将有一个用于前端 HTML 的 Angular 项目,然后前端应用程序将由 Angular 服务填充,以向后端服务发出请求。

基于令牌的身份验证后端

在后端项目中,主要有三个文件:

  • package.json 用于依赖管理。
  • models/User.js 包含一个用户模型,用于对用户进行数据库操作。
  • server.js 用于项目引导和请求处理。

就是这样!这个项目非常简单,因此您无需深入研究即可轻松理解主要概念。

{
    "name": "angular-restful-auth",
    "version": "0.0.1",
    "dependencies": {
        "body-parser": "^1.20.2",
        "express": "4.x",
        "express-jwt": "8.4.1",
        "jsonwebtoken": "9.0.0",
        "mongoose": "7.3.1",
        "morgan": "latest"
    },
    "engines": {
        "node": ">=0.10.0"
    }
}
 

package.json 包含项目的依赖项: express 用于 MVC,body-parser 用于模拟 post Node.js 中的请求处理,morgan 用于请求日志记录,mongoose 用于我们的 ORM 框架连接到 MongoDB,和 jsonwebtoken 用于使用我们的用户模型创建 JWT 令牌。还有一个名为 engines 的属性,表示该项目是使用 Node.js 版本 >= 0.10.0 制作的。这对于 Heroku 等 PaaS 服务很有用。我们还将在另一节中讨论该主题。

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const UserSchema = new Schema({
  email: String,
  password: String,
  token: String
});

module.exports = mongoose.model('User', UserSchema);
 

我们说过我们将使用用户模型有效负载生成令牌。这个模型帮助我们对MongoDB进行用户操作。在User.js中,定义了用户模式并使用猫鼬模型创建了用户模型。该模型已准备好进行数据库操作。

我们的依赖关系已经定义,我们的用户模型也已经定义,所以现在让我们将所有这些组合起来构建一个用于处理特定请求的服务。

// Required Modules
const express    = require("express");
const morgan     = require("morgan");
const bodyParser = require("body-parser");
const jwt        = require("jsonwebtoken");
const mongoose   = require("mongoose");
const app        = express();
 

在 Node.js 中,您可以使用 require 在项目中包含模块。首先,我们需要将必要的模块导入到项目中:

const port = process.env.PORT || 3001;
const User     = require('./models/User');

// Connect to DB
mongoose.connect(process.env.MONGO_URL);
 

我们的服务将通过特定端口提供服务。如果系统环境变量中定义了任何端口变量,则可以使用它,或者我们定义了端口 3001。之后,包含了User模型,并建立了数据库连接,以进行一些用户操作。不要忘记为数据库连接 URL 定义一个环境变量 MONGO_URL

Ini adalah kelebihan paling biasa bagi pengesahan dan komunikasi berasaskan token. Ini menyimpulkan perbincangan teori dan seni bina tentang pengesahan berasaskan token. Sudah tiba masanya untuk melihat contoh praktikal.

Contoh permohonan

Anda akan melihat dua aplikasi yang menunjukkan pengesahan berasaskan token: 🎜
  1. Halaman belakang pengesahan berasaskan token
  2. Ujung hadapan pengesahan berasaskan token
🎜Dalam projek bahagian belakang, akan ada pelaksanaan perkhidmatan, dan keputusan perkhidmatan akan dalam format JSON. Tiada pandangan dikembalikan daripada perkhidmatan. Dalam projek bahagian hadapan, akan ada projek Angular untuk HTML bahagian hadapan dan kemudian aplikasi bahagian hadapan akan diisi oleh perkhidmatan Angular untuk membuat permintaan kepada perkhidmatan bahagian belakang. 🎜

Halaman belakang pengesahan berasaskan token

🎜Dalam projek bahagian belakang, terdapat tiga fail utama: 🎜
  • package.json digunakan untuk pengurusan pergantungan.
  • models/User.js mengandungi model pengguna untuk operasi pangkalan data pada pengguna.
  • server.js digunakan untuk bootstrap projek dan pemprosesan permintaan.
🎜Itu sahaja! Projek ini sangat mudah supaya anda boleh memahami konsep utama dengan mudah tanpa perlu mendalaminya. 🎜
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(morgan("dev"));
app.use(function(req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization');
    next();
});

, 🎜package.json mengandungi kebergantungan projek: express untuk MVC, body-parser digunakan untuk mensimulasikan pemprosesan permintaan pos dalam Node.js, morgan digunakan untuk pengelogan permintaan, mongoose digunakan untuk menyambungkan rangka kerja ORM kami kepada MongoDB dan jsonwebtoken digunakan untuk mencipta token JWT menggunakan model pengguna kami. Terdapat juga atribut yang dipanggil engines yang menunjukkan bahawa projek itu dibuat menggunakan versi Node.js >= 0.10.0. Ini berguna untuk perkhidmatan PaaS seperti Heroku. Kami juga akan membincangkan topik ini dalam bahagian lain. 🎜
app.post('/authenticate', async function(req, res) {
    try {
      const user = await User.findOne({ email: req.body.email, password: req.body.password }).exec();
      if (user) {
        res.json({
          type: true,
          data: user,
          token: user.token
        });
      } else {
        res.json({
          type: false,
          data: "Incorrect email/password"
        });
      }
    } catch (err) {
      res.json({
        type: false,
        data: "Error occurred: " + err
      });
    }
  });
, 🎜Kami berkata kami akan menggunakan muatan model pengguna untuk menjana token. Model ini membantu kami melaksanakan operasi pengguna pada MongoDB. Dalam User.js, corak pengguna ditentukan dan model pengguna dibuat menggunakan model mongoose. Model sedia untuk operasi pangkalan data. 🎜 🎜Kebergantungan kami ditakrifkan, model pengguna kami ditakrifkan, jadi sekarang mari kita susun semuanya untuk membina perkhidmatan yang mengendalikan permintaan tertentu. 🎜
 app.post('/signin', async function(req, res) {
    try {
      const existingUser = await User.findOne({ email: req.body.email }).exec();
      if (existingUser) {
        res.json({
          type: false,
          data: "User already exists!"
        });
      } else {
        const userModel = new User();
        userModel.email = req.body.email;
        userModel.password = req.body.password;
        const savedUser = await userModel.save();
        savedUser.token = jwt.sign(savedUser.toObject(), process.env.JWT_SECRET);
        const updatedUser = await savedUser.save();
        res.json({
          type: true,
          data: updatedUser,
          token: updatedUser.token
        });
      }
    } catch (err) {
      res.json({
        type: false,
        data: "Error occurred: " + err
      });
    }
  });
, 🎜Dalam Node.js, anda boleh menggunakan require untuk memasukkan modul dalam projek anda. Pertama, kita perlu mengimport modul yang diperlukan ke dalam projek: 🎜
app.get('/me', ensureAuthorized, async function(req, res) {
    try {
      const user = await User.findOne({ token: req.token }).exec();
      res.json({
        type: true,
        data: user
      });
    } catch (err) {
      res.json({
        type: false,
        data: "Error occurred: " + err
      });
    }
  });
, 🎜Perkhidmatan kami akan disediakan melalui port tertentu. Anda boleh menggunakannya jika mana-mana pembolehubah port ditakrifkan dalam pembolehubah persekitaran sistem atau kami telah menentukan port 3001. Selepas itu, model Pengguna disertakan dan sambungan pangkalan data diwujudkan untuk beberapa operasi pengguna. Jangan lupa untuk menentukan pembolehubah persekitaran MONGO_URL untuk URL sambungan pangkalan data. 🎜
function ensureAuthorized(req, res, next) {
    var bearerToken;
    var bearerHeader = req.headers["authorization"];
    if (typeof bearerHeader !== 'undefined') {
        var bearer = bearerHeader.split(" ");
        bearerToken = bearer[1];
        req.token = bearerToken;
        next();
    } else {
        res.send(403);
    }
}
, 🎜Dalam bahagian di atas, kami membuat beberapa konfigurasi menggunakan Express untuk mensimulasikan pemprosesan permintaan HTTP dalam Node. Kami membenarkan permintaan daripada domain yang berbeza untuk membangunkan sistem bebas pelanggan. Jika anda tidak membenarkan ini, anda akan mencetuskan ralat CORS (Cross-Origin Request Sharing) dalam pelayar web anda. 🎜
  • Access-Control-Allow-Origin 允许所有域。
  • 您可以向此服务发送 POSTGET 请求。
  • X-Requested-Withcontent-type 标头是允许的。
app.post('/authenticate', async function(req, res) {
    try {
      const user = await User.findOne({ email: req.body.email, password: req.body.password }).exec();
      if (user) {
        res.json({
          type: true,
          data: user,
          token: user.token
        });
      } else {
        res.json({
          type: false,
          data: "Incorrect email/password"
        });
      }
    } catch (err) {
      res.json({
        type: false,
        data: "Error occurred: " + err
      });
    }
  });
 

我们已经导入了所有必需的模块并定义了我们的配置,所以现在是时候定义请求处理程序了。在上面的代码中,每当你使用用户名和密码向 /authenticate 发出 POST 请求时,你都会得到一个 JWT 令牌。首先,使用用户名和密码处理数据库查询。如果用户存在,则用户数据将与其令牌一起返回。但是如果没有与用户名和/或密码匹配的用户怎么办?

 app.post('/signin', async function(req, res) {
    try {
      const existingUser = await User.findOne({ email: req.body.email }).exec();
      if (existingUser) {
        res.json({
          type: false,
          data: "User already exists!"
        });
      } else {
        const userModel = new User();
        userModel.email = req.body.email;
        userModel.password = req.body.password;
        const savedUser = await userModel.save();
        savedUser.token = jwt.sign(savedUser.toObject(), process.env.JWT_SECRET);
        const updatedUser = await savedUser.save();
        res.json({
          type: true,
          data: updatedUser,
          token: updatedUser.token
        });
      }
    } catch (err) {
      res.json({
        type: false,
        data: "Error occurred: " + err
      });
    }
  });
 

当您使用用户名和密码向 /signin 发出 POST 请求时,将使用发布的用户信息创建一个新用户。在 14th 行,您可以看到使用 jsonwebtoken 模块生成了一个新的 JSON 令牌,该令牌已分配给 jwt 变量。认证部分没问题。如果我们尝试访问受限端点怎么办?我们如何设法访问该端点?

app.get('/me', ensureAuthorized, async function(req, res) {
    try {
      const user = await User.findOne({ token: req.token }).exec();
      res.json({
        type: true,
        data: user
      });
    } catch (err) {
      res.json({
        type: false,
        data: "Error occurred: " + err
      });
    }
  });
 

当您向 /me 发出 GET 请求时,您将获得当前用户信息,但为了继续请求的端点,确保Authorized函数将被执行。

function ensureAuthorized(req, res, next) {
    var bearerToken;
    var bearerHeader = req.headers["authorization"];
    if (typeof bearerHeader !== 'undefined') {
        var bearer = bearerHeader.split(" ");
        bearerToken = bearer[1];
        req.token = bearerToken;
        next();
    } else {
        res.send(403);
    }
}
 

在该函数中,拦截请求头,并提取authorization头。如果此标头中存在承载令牌,则该令牌将分配给 req.token 以便在整个请求中使用,并且可以使用 next( )。如果令牌不存在,您将收到 403(禁止)响应。让我们回到处理程序 /me,并使用 req.token 使用此令牌获取用户数据。每当您创建新用户时,都会生成一个令牌并将其保存在数据库的用户模型中。这些令牌是独一无二的。

对于这个简单的项目,我们只有三个处理程序。之后,您将看到:

process.on('uncaughtException', function(err) {
    console.log(err);
});
 

如果发生错误,Node.js 应用程序可能会崩溃。使用上面的代码,可以防止崩溃,并在控制台中打印错误日志。最后,我们可以使用以下代码片段启动服务器。

// Start Server
app.listen(port, function () {
    console.log( "Express server listening on port " + port);
});
 

总结一下:

  • 模块已导入。
  • 配置已完成。
  • 已定义请求处理程序。
  • 定义中间件是为了拦截受限端点。
  • 服务器已启动。

我们已经完成了后端服务。为了让多个客户端可以使用它,您可以将这个简单的服务器应用程序部署到您的服务器上,或者也可以部署在 Heroku 中。项目根文件夹中有一个名为 Procfile 的文件。让我们在 Heroku 中部署我们的服务。

Heroku 部署

您可以从此 GitHub 存储库克隆后端项目。

我不会讨论如何在 Heroku 中创建应用程序;如果您之前没有创建过 Heroku 应用程序,可以参考这篇文章来创建 Heroku 应用程序。创建 Heroku 应用程序后,您可以使用以下命令将目标添加到当前项目:

git remote add heroku <your_heroku_git_url>

现在您已经克隆了一个项目并添加了一个目标。在 git addgit commit 之后,您可以通过执行 git push heroku master 将代码推送到 Heroku。当您成功推送项目时,Heroku 将执行 npm install 命令将依赖项下载到 Heroku 上的 temp 文件夹中。之后,它将启动您的应用程序,您可以使用 HTTP 协议访问您的服务。

基于令牌的-auth-frontend

在前端项目中,您将看到一个 Angular 项目。在这里,我只提及前端项目中的主要部分,因为 Angular 不是一个教程可以涵盖的内容。

您可以从此 GitHub 存储库克隆该项目。在此项目中,您将看到以下文件夹结构:

Pengesahan berasaskan token dengan Angular dan Node

我们拥有三个组件——注册、配置文件和登录——以及一个身份验证服务。

您的app.component.html 如下所示:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
  </head>
  <body>
    <nav class="navbar navbar-expand-lg bg-body-tertiary">
        <div class="container-fluid">
          <a class="navbar-brand" href="#">Home</a>
          <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav">
              
              <li class="nav-item"><a class="nav-link" routerLink="/profile">Me</a></li>
              <li class="nav-item"><a class="nav-link" routerLink="/login">Signin</a></li>
              <li class="nav-item"><a class="nav-link" routerLink="/signup">Signup</a></li>
              <li class="nav-item"><a class="nav-link" (click)="logout()">Logout</a></li>
            </ul>
          </div>
        </div>
      </nav>

    <div class="container">
        <router-outlet></router-outlet>
    </div> 

  </body>
</html>
 

在主组件文件中,<router-outlet></router-outlet> 定义各个组件的路由。

auth.service.ts 文件中,我们定义 AuthService 类,该类通过 API 调用来处理身份验证,以登录、验证 Node.js 应用程序的 API 端点。

import { Injectable } from '@angular/core';
import { HttpClient,HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private apiUrl = 'your_node_app_url';
  public token: string ='';


  constructor(private http: HttpClient) {
    
  }


  signin(username: string, password: string): Observable<any> {
    const data = { username, password };
    return this.http.post(`${this.apiUrl}/signin`, data);
  }

 

  authenticate(email: string, password: string): Observable<any> {
    const data = { email, password };
    console.log(data)

    return this.http.post(`${this.apiUrl}/authenticate`, data)
      .pipe(
        tap((response:any) => {
          this.token = response.data.token; // Store the received token
          localStorage.setItem('token',this.token)
          console.log(this.token)
        })
      );
  }

  profile(): Observable<any> {
    const headers = this.createHeaders();
    return this.http.get(`${this.apiUrl}/me`,{ headers });
  }


  private createHeaders(): HttpHeaders {
    let headers = new HttpHeaders({
      'Content-Type': 'application/json',
    });

    if (this.token) {
      headers = headers.append('Authorization', `Bearer ${this.token}`);
    }

    return headers;
  }

  logout(): void {
    
    localStorage.removeItem('token');
  }
 
  
}


authenticate() 方法中,我们向 API 发送 POST 请求并对用户进行身份验证。从响应中,我们提取令牌并将其存储在服务的 this.token 属性和浏览器的 localStorage 中,然后将响应作为 Observable 返回。

profile() 方法中,我们通过在 Authorization 标头中包含令牌来发出 GET 请求以获取用户详细信息。

createHeaders() 方法在发出经过身份验证的 API 请求时创建包含身份验证令牌的 HTTP 标头。当用户拥有有效令牌时,它会添加一个授权标头。该令牌允许后端 API 对用户进行身份验证。

如果身份验证成功,用户令牌将存储在本地存储中以供后续请求使用。该令牌也可供所有组件使用。如果身份验证失败,我们会显示一条错误消息。

不要忘记将服务 URL 放入上面代码中的 baseUrl 中。当您将服务部署到 Heroku 时,您将获得类似 appname.herokuapp.com 的服务 URL。在上面的代码中,您将设置 var baseUrl = "appname.herokuapp.com"

注销功能从本地存储中删除令牌。

signup.component.ts 文件中,我们实现了 signup () 方法,该方法获取用户提交的电子邮件和密码并创建一个新用户。

import { Component } from '@angular/core';
import { AuthService } from '../auth.service';



@Component({
  selector: 'app-signup',
  templateUrl: './signup.component.html',
  styleUrls: ['./signup.component.css']
})
export class SignupComponent {
  password: string = '';
  email: string = '';
  

  constructor(private authService:AuthService){}

  signup(): void {
    this.authService.signin(this.email, this.password).subscribe(
      (response) => {
        // success response
        console.log('Authentication successful', response);
       
      },
      (error) => {
        // error response
        console.error('Authentication error', error);
      }
    );
  }
}
  login.component.ts 文件看起来与注册组件类似。  
import { Component } from '@angular/core';
import { AuthService } from '../auth.service';



@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent {
    
  email: string = '';
  password: string = '';

  constructor(private authService: AuthService) {}

  login(): void {
    this.authService.authenticate(this.email, this.password).subscribe(
      (response) => {
        // success response
        console.log('Signin successful', response);
       
      },
      (error) => {
        // error response
        console.error('Signin error', error);
      }
    );
  }
}

配置文件组件使用用户令牌来获取用户的详细信息。每当您向后端的服务发出请求时,都需要将此令牌放入标头中。 profile.component.ts 如下所示:

import { Component } from '@angular/core';
import { AuthService } from '../auth.service';
@Component({
  selector: 'app-profile',
  templateUrl: './profile.component.html',
  styleUrls: ['./profile.component.css']
})

export class ProfileComponent {
  myDetails: any;

  constructor(private authService: AuthService) { }

  ngOnInit(): void {
    this.getProfileData();
  }
  getProfileData(): void {
    this.authService.me().subscribe(
      (response: any) => {
        this.myDetails = response;
        console.log('User Data:', this.myDetails);
      },
      (error: any) => {
        console.error('Error retrieving profile data');
      }
    );
  }
 

在上面的代码中,每个请求都会被拦截,并在标头中放入授权标头和值。然后,我们将用户详细信息传递到 profile.component.html 模板。

<h2>User profile </h2>

<div class="row">
    <div class="col-lg-12">
        <p>{{myDetails.data.id}}</p>
        <p>{{myDetails.data.email}}</p>
    </div>
</div>

最后,我们在 app.routing.module.ts 中定义路由。

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { ProfileComponent } from './profile/profile.component';
import { SignupComponent } from './signup/signup.component';

const routes: Routes = [
  {path:'signup' , component:SignupComponent},
  {path:'login' , component:LoginComponent},
  { path: 'profile', component: ProfileComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
 

从上面的代码中您可以很容易地理解,当您转到/时,将呈现app.component.html页面。另一个例子:如果您转到/signup,则会呈现signup.component.html。这个渲染操作将在浏览器中完成,而不是在服务器端。

结论

基于令牌的身份验证系统可帮助您在开发独立于客户端的服务时构建身份验证/授权系统。通过使用这项技术,您将只需专注于您的服务(或 API)。

身份验证/授权部分将由基于令牌的身份验证系统作为服务前面的一层进行处理。您可以从任何客户端(例如网络浏览器、Android、iOS 或桌面客户端)访问和使用服务。

Atas ialah kandungan terperinci Pengesahan berasaskan token dengan Angular dan Node. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn