<!DOCTYPE html>
    <html lang="vi" xmlns="http://www.w3.org/1999/xhtml" prefix="og: http://ogp.me/ns#">
    <head>
<title>Cách triển khai kiểm soát quyền truy cập theo vai trò trong API Express.js REST bằng Passport.js và JWT</title>
<meta name="description" content="Cách triển khai kiểm soát quyền truy cập theo vai trò trong API Express.js REST bằng Passport.js và JWT - Savefile - Tin Tức -...">
<meta name="author" content=".: Nguoicodonvn2008.info - Cõi lòng người cô đơn :.">
<meta name="copyright" content=".: Nguoicodonvn2008.info - Cõi lòng người cô đơn :. [admin@nguoicodonvn2008.info]">
<meta name="robots" content="index, archive, follow, noodp">
<meta name="googlebot" content="index,archive,follow,noodp">
<meta name="msnbot" content="all,index,follow">
<meta name="generator" content="NukeViet v4.5">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta property="og:title" content="Cách triển khai kiểm soát quyền truy cập theo vai trò trong API Express.js REST bằng Passport.js và JWT">
<meta property="og:type" content="website">
<meta property="og:description" content="Savefile - Tin Tức -...">
<meta property="og:site_name" content=".&#x3A; Nguoicodonvn2008.info - Cõi lòng người cô đơn &#x3A;.">
<meta property="og:url" content="https://www.nguoicodonvn2008.info/vi/news/savefile/kien-thuc-may-tinh/cach-trien-khai-kiem-soat-quyen-truy-cap-theo-vai-tro-trong-api-express-js-rest-bang-passport-js-va-jwt-7333.html">
<link rel="shortcut icon" href="https://nguoicodonvn2008.info/favicon.ico">
<link rel="canonical" href="https://www.nguoicodonvn2008.info/vi/news/savefile/kien-thuc-may-tinh/cach-trien-khai-kiem-soat-quyen-truy-cap-theo-vai-tro-trong-api-express-js-rest-bang-passport-js-va-jwt-7333.html">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/" title="Tin Tức" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/karaoke-dual/" title="Tin Tức - Karaoke Dual" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/nhac-tre/" title="Tin Tức - Nhạc trẻ" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/tru-tinh/" title="Tin Tức - Trữ tình" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/nuoc-ngoai/" title="Tin Tức - Nước ngoài" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/remix/" title="Tin Tức - Remix" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/tam-su-tinh-yeu/" title="Tin Tức - Tâm sự tình yêu" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/tho-suu-tam/" title="Tin Tức - Thơ sưu tầm" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/cuoc-song/" title="Tin Tức - Cuộc sống" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/phan-mem/" title="Tin Tức - Phần mềm" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/kien-thuc-may-tinh/" title="Tin Tức - Kiến thức máy tính" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/hoc-tap/" title="Tin Tức - Học tập" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/tai-lieu/" title="Tin Tức - Tài liệu" type="application/rss+xml">
<link rel="alternate" href="https://nguoicodonvn2008.info/vi/news/rss/de-thi/" title="Tin Tức - Đề thi" type="application/rss+xml">
<link rel="preload" as="style" href="https://nguoicodonvn2008.info/assets/css/font-awesome.min.css" type="text/css">
<link rel="preload" as="style" href="https://nguoicodonvn2008.info/themes/default/css/bootstrap.non-responsive.css" type="text/css">
<link rel="preload" as="style" href="https://nguoicodonvn2008.info/themes/default/css/style.css" type="text/css">
<link rel="preload" as="style" href="https://nguoicodonvn2008.info/themes/default/css/style.non-responsive.css" type="text/css">
<link rel="preload" as="style" href="https://nguoicodonvn2008.info/themes/default/css/news.css" type="text/css">
<link rel="preload" as="style" href="https://nguoicodonvn2008.info/themes/default/css/custom.css" type="text/css">
<link rel="preload" as="script" href="https://nguoicodonvn2008.info/assets/js/jquery/jquery.min.js" type="text/javascript">
<link rel="preload" as="script" href="https://nguoicodonvn2008.info/assets/js/language/vi.js" type="text/javascript">
<link rel="preload" as="script" href="https://nguoicodonvn2008.info/assets/js/DOMPurify/purify3.js" type="text/javascript">
<link rel="preload" as="script" href="https://nguoicodonvn2008.info/assets/js/global.js" type="text/javascript">
<link rel="preload" as="script" href="https://nguoicodonvn2008.info/assets/js/site.js" type="text/javascript">
<link rel="preload" as="script" href="https://nguoicodonvn2008.info/themes/default/js/news.js" type="text/javascript">
<link rel="preload" as="script" href="https://nguoicodonvn2008.info/themes/default/js/main.js" type="text/javascript">
<link rel="preload" as="script" href="https://nguoicodonvn2008.info/themes/default/js/custom.js" type="text/javascript">
<link rel="preload" as="script" href="https://nguoicodonvn2008.info/themes/default/js/bootstrap.min.js" type="text/javascript">
<link rel="stylesheet" href="https://nguoicodonvn2008.info/assets/css/font-awesome.min.css">
<link rel="stylesheet" href="https://nguoicodonvn2008.info/themes/default/css/bootstrap.non-responsive.css">
<link rel="stylesheet" href="https://nguoicodonvn2008.info/themes/default/css/style.css">
<link rel="stylesheet" href="https://nguoicodonvn2008.info/themes/default/css/style.non-responsive.css">
<link rel="StyleSheet" href="https://nguoicodonvn2008.info/themes/default/css/news.css">
<link rel="stylesheet" href="https://nguoicodonvn2008.info/themes/default/css/custom.css">
<style type="text/css">
	body{background: #fff;}
</style>
    </head>
    <body>
<div id="print">
	<div id="hd_print">
		<h2 class="pull-left">.&#x3A; Nguoicodonvn2008.info - Cõi lòng người cô đơn &#x3A;.</h2>
		<p class="pull-right"><a title=".&#x3A; Nguoicodonvn2008.info - Cõi lòng người cô đơn &#x3A;." href="https://nguoicodonvn2008.info/">https://nguoicodonvn2008.info</a></p>
	</div>
	<div class="clear"></div>
	<hr />
	<div id="content">
		<h1>Cách triển khai kiểm soát quyền truy cập theo vai trò trong API Express.js REST bằng Passport.js và JWT</h1>
		<ul class="list-inline">
			<li>Thứ tư - 26/07/2023 00:50</li>
			<li class="hidden-print txtrequired"><em class="fa fa-print">&nbsp;</em><a title="In ra" href="javascript:;" onclick="window.print()">In ra</a></li>
			<li class="hidden-print txtrequired"><em class="fa fa-power-off">&nbsp;</em><a title="Đóng cửa sổ này" href="javascript:;" onclick="window.close()">Đóng cửa sổ này</a></li>
		</ul>
		<div class="clear"></div>
		<div id="hometext">
		</div>
				<div class="imghome">
			<img alt="Cách triển khai kiểm soát quyền truy cập theo vai trò trong API Express.js REST bằng Passport.js và JWT" src="https://st.quantrimang.com/photos/image/2023/07/25/AcessControl.jpg" width="460" class="img-thumbnail" />
		</div>
		<div class="clear"></div>
		<div id="bodytext" class="clearfix">
			<p style="text-align: justify;"><strong>Kiểm soát truy cập theo vai trò</strong>&nbsp;là cơ chế xác thực an toàn. Bạn có thể dùng nó để hạn chế quyền truy cập tới tài nguyên nào đó.</p>

<p style="text-align: justify;"><img alt="Kiểm soát quyền truy cập theo vai trò" data-i="0" data-src="https://st.quantrimang.com/photos/image/2023/07/25/REST-API-ksoat-truy-cap-7.jpg" data-was-processed="true" height="340" src="https://st.quantrimang.com/photos/image/2023/07/25/REST-API-ksoat-truy-cap-7.jpg" width="650" /></p>

<p style="text-align: justify;">Kiểu xác thực này giúp quản trị viên hệ thống kiểm soát quyền truy cập theo vai trò người dùng. Mức độ kiểm soát chi tiết này thêm lớp bảo mật, cho phép ứng dụng chặn truy cập bất hợp pháp.</p>

<h2 style="text-align: justify;">Triển khai quyền truy cập theo vai trò bằng Passport.js và JWT</h2>

<p style="text-align: justify;">Bạn có hai cách để thực hiện việc này bao gồm dùng thư viện chuyên dụng như&nbsp;<strong>AcessControl</strong>&nbsp;hoặc tận dụng thư viện xác thực hiện tại để thực hiện cơ chế này.</p>

<p style="text-align: justify;"><img alt="Kiểm soát truy cập" data-adbro-processed="true" data-i="1" data-src="https://st.quantrimang.com/photos/image/2023/07/25/AcessControl.jpg" data-was-processed="true" height="325" src="https://st.quantrimang.com/photos/image/2023/07/25/AcessControl.jpg" width="650" /></p>

<div style="text-align: justify;">&nbsp;</div>

<p style="text-align: justify;">Ở đây, JSON Web Token (JWT) cung cấp cách an toàn để chuyển thông tin xác thực, còn Passport.js đơn giản hóa quá trình xác thực bằng cách cung cấp middleware xác thực linh hoạt.</p>

<p style="text-align: justify;">Dùng phương pháp này, bạn có thể phân bổ vai trò người dùng, mã hóa chúng trong JWT khi họ xác thực. Sau đó, bạn có thể dùng JWT để xác minh danh tính &amp; vai trò của người dùng trong các truy vấn tiếp theo, cho phép kiểm soát truy cập và phân quyền theo vai trò.</p>

<p style="text-align: justify;">Cả hai phương pháp đều có ưu điểm riêng. Chúng hoạt động hiệu quả trong việc kiểm soát truy cập theo vai trò. Lựa chọn phương pháp nào tùy thuộc vào yêu cầu dự án của bạn.</p>

<h2 style="text-align: justify;">Thiết lập dự án Express.js</h2>

<p style="text-align: justify;">Để bắt đầu, thiết lập dự án Express.js cục bộ. Sau đó, cài những gói này:</p>

<pre id="pre0">
<code>npm install cors dotenv mongoose cookie-parser jsonwebtoken mongodb \
  passport passport-local</code></pre>

<p style="text-align: justify;">Tiếp theo, tạo database MongoDB hoặc thiết lập một nhóm trên MongoDB Atlas. Sao chép kết nối database URL và thêm nó vào file<strong>&nbsp;.env</strong>&nbsp;trong thư mục gốc của dự án:</p>

<pre id="pre1">
<code>CONNECTION_URI=&quot;connection URI&quot;</code></pre>

<h3 style="text-align: justify;">Cấu hình kết nối database</h3>

<p style="text-align: justify;">Trong thư mục gốc, tạo file mới&nbsp;<strong>utils/db.js</strong>, thêm code bên dưới để thiết lập kết nối tới nhóm MongoDB đang chạy trên Atlas bằng&nbsp;<a data-type="internal" href="https://quantrimang.com/cong-nghe/cach-dung-mongoose-trong-ung-dung-express-196123" rel="noopener" target="_blank" title="Cách dùng Mongoose trong ứng dụng Express">Mongoose</a>.</p>

<pre id="pre2">
<code>const mongoose = require(&#039;mongoose&#039;);

const connectDB = async () =&gt; {
  try {
    await mongoose.connect(process.env.CONNECTION_URI);
    console.log(&quot;Connected to MongoDB!&quot;);
  } catch (error) {
    console.error(&quot;Error connecting to MongoDB:&quot;, error);
  }
};

module.exports = connectDB;</code></pre>

<h3 style="text-align: justify;">Xác định mô hình dữ liệu</h3>

<p style="text-align: justify;">Trong thư mục gốc, tạo file mới&nbsp;<strong>model/user.model.js&nbsp;</strong>và thêm code sau để xác định mô hình dữ liệu cho người dùng bằng Mongoose.</p>

<pre id="pre3">
<code>const mongoose = require(&#039;mongoose&#039;);

const userSchema = new mongoose.Schema({
  username: String,
  password: String,
  role: String
});

module.exports = mongoose.model(&#039;User&#039;, userSchema);</code></pre>

<h2 style="text-align: justify;">Tạo controller cho API Endpoints</h2>

<p style="text-align: justify;">Tạo một file&nbsp;<strong>controllers/user.controller.js&nbsp;</strong>mới trong thư mục gốc và thêm code bên dưới.</p>

<p style="text-align: justify;">Đầu tiên, tạo những import này:</p>

<pre id="pre4">
<code>const User = require(&#039;../models/user.model&#039;);
const passport = require(&#039;passport&#039;);
const { generateToken } = require(&#039;../middleware/auth&#039;);
require(&#039;../middleware/passport&#039;)(passport);</code></pre>

<div style="text-align: justify;"><iframe allow="attribution-reporting" allowtransparency="true" browsingtopics="true" data-google-container-id="a!3" data-google-query-id="CJ7yq83Jq4ADFQRVDwIdsscAoA" data-load-complete="true" frameborder="0" height="0" hspace="0" id="aswift_2" marginheight="0" marginwidth="0" name="aswift_2" sandbox="allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-top-navigation-by-user-activation" scrolling="no" vspace="0" width="694"></iframe></div>

<p style="text-align: justify;">Tiếp theo, xác định logic quản lý đăng ký người dùng và chức năng đăng nhập:</p>

<pre id="pre5">
<code>exports.registerUser = async (req, res) =&gt; {
  const { username, password, role } = req.body;

  try {
    await User.create({ username, password, role });
    res.status(201).json({ message: &#039;User registered successfully&#039; });
  } catch (error) {
    console.log(error);
    res.status(500).json({ message: &#039;An error occurred!&#039; });
  }
};

exports.loginUser = (req, res, next) =&gt; {
  passport.authenticate(&#039;local&#039;, { session: false }, (err, user, info) =&gt; {
    if (err) {
      console.log(err);

      return res.status(500).json({
        message: &#039;An error occurred while logging in&#039;
      });
    }

    if (!user) {
      return res.status(401).json({
        message: &#039;Invalid login credentials&#039;
      });
    }

    req.login(user, { session: false }, (err) =&gt; {
      if (err) {
        console.log(err);

        return res.status(500).json({
          message: &#039;An error occurred while logging in&#039;
        });
      }

      const { _id, username, role } = user;
      const payload = { userId: _id, username, role };
      const token = generateToken(payload);
      res.cookie(&#039;token&#039;, token, { httpOnly: true });
      return res.status(200).json({ message: &#039;Login successful&#039; });
    });
  })(req, res, next);
};</code></pre>

<p style="text-align: justify;">Hàm&nbsp;<strong>registerUser</strong>&nbsp;xử lý đăng ký người dùng mới bằng cách truy xuất tên người dùng, mật khẩu và vai trò từ phần nội dung truy vấn. Sau đó nó tạo một mục người dùng mới trong database và phản hồi bằng một thông báo thành công hoặc lỗi nếu có bất kỳ vấn đề xảy ra trong suốt quá trình này.</p>

<p style="text-align: justify;">Mặt khác, hàm&nbsp;<strong>loginUser</strong>&nbsp;tạo điều kiện cho người dùng bằng cách sử dụng chiến thuật xác thực cục bộ được cung cấp bởi Passport.js. Nó xác thực thông tin của người dùng và trả về token sau khi đăng nhập thành công. Mã thông báo đó được lưu trong cookie cho các yêu cầu xác thực tiếp theo. Nếu có lỗi xảy ra trong suốt quá trình đăng nhập, nó sẽ trả về một thông báo phù hợp.</p>

<p style="text-align: justify;">Cuối cùng, thêm code triển khai logic tìm nạp tất cả dữ liệu của người dùng từ database. Bài viết dùng endpoint này làm route hạn chế để đảm bảo chỉ người dùng được xác thực có quyền&nbsp;<strong>admin</strong>&nbsp;mới có thể truy cập endpoint này.</p>

<pre id="pre6">
<code>exports.getUsers = async (req, res) =&gt; {
  try {
    const users = await User.find({});
    res.json(users);
  } catch (error) {
    console.log(error);
    res.status(500).json({ message: &#039;An error occurred!&#039; });
  }
};</code></pre>

<h3 style="text-align: justify;">Thiết lập chiến thuật xác thực cục bộ Passport.js</h3>

<p style="text-align: justify;">Để xác thực người dùng sau khi họ cung cấp thông tin đăng nhập, bạn cần thiết lập chiến thuật xác thực cục bộ.</p>

<div style="text-align: justify;"><iframe allow="attribution-reporting" allowtransparency="true" browsingtopics="true" data-google-container-id="a!4" data-google-query-id="CKPdzc7Jq4ADFQFqDwIdSfoPNA" data-load-complete="true" frameborder="0" height="0" hspace="0" id="aswift_3" marginheight="0" marginwidth="0" name="aswift_3" sandbox="allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-top-navigation-by-user-activation" scrolling="no" vspace="0" width="694"></iframe></div>

<p style="text-align: justify;">Tạo một file&nbsp;<strong>middleware/passport.js</strong>&nbsp;mới trong thư mục gốc và thêm code sau.</p>

<pre id="pre7">
<code>const LocalStrategy = require(&#039;passport-local&#039;).Strategy;
const User = require(&#039;../models/user.model&#039;);

module.exports = (passport) =&gt; {
  passport.use(
    new LocalStrategy(async (username, password, done) =&gt; {
      try {
        const user = await User.findOne({ username });

        if (!user) {
          return done(null, false);
        }

        if (user.password !== password) {
          return done(null, false);
        }

        return done(null, user);
      } catch (error) {
        return done(error);
      }
    })
  );
};</code></pre>

<p style="text-align: justify;">Code này xác định một chiến thuật passport.js cục bộ để xác thực người dùng dựa trên tên người dùng và mật khẩu được cung cấp.</p>

<p style="text-align: justify;">Đầu tiên, nó yêu cầu database để tìm người dùng với username phù hợp và sau đó tiếp tục xác thực mật khẩu. Kết quả, nó trả về đối tượng người dùng được xác thực nếu quá trình đăng nhập thành công.</p>

<h3 style="text-align: justify;">Tạo middleware xác thực JWT</h3>

<p style="text-align: justify;">Bên trong thư mục&nbsp;<strong>middleware</strong>, tạo một file auth.js mới và thêm code sau để xác định middleware tạo &amp; xác minh JWT.</p>

<pre id="pre8">
<code>const jwt = require(&#039;jsonwebtoken&#039;);
const secretKey = process.env.SECRET_KEY;

const generateToken = (payload) =&gt; {
  const token = jwt.sign(payload, secretKey, { expiresIn: &#039;1h&#039; });
  return token;
};

const verifyToken = (requiredRole) =&gt; (req, res, next) =&gt; {
  const token = req.cookies.token;

  if (!token) {
    return res.status(401).json({ message: &#039;No token provided&#039; });
  }

  jwt.verify(token, secretKey, (err, decoded) =&gt; {
    if (err) {
      return res.status(401).json({ message: &#039;Invalid token&#039; });
    }

    req.userId = decoded.userId; 

    if (decoded.role !== requiredRole) {
      return res.status(403).json({
        message: &#039;You do not have the authorization and permissions to access this resource.&#039;
      });
    }

    next();
  });
};

module.exports = { generateToken, verifyToken };</code></pre>

<p style="text-align: justify;">Hàm&nbsp;<strong>generateToken</strong>&nbsp;tạo JWT với thời gian hết hạn được chỉ định, còn hàm&nbsp;<strong>verifyToken</strong>&nbsp;kiểm tra xem liệu token có tồn tại và hợp lệ hay không. Ngoài ra, nó cũng xác thực rằng token được giải mã chứa vai trò bắt buộc, về cơ bản, đảm bảo chỉ người dùng có thẩm quyền và được phép mới truy cập được.</p>

<p style="text-align: justify;">Để ký JWT duy nhất theo cách duy nhất, bạn cần tạo khóa bí mật riêng và thêm nó vào file&nbsp;<strong>.env</strong>&nbsp;như bên dưới.</p>

<pre id="pre9">
<code>SECRET_KEY=&quot;This is a sample secret key.&quot;</code></pre>

<h2 style="text-align: justify;">Xác định định tuyến API</h2>

<p style="text-align: justify;">Trong thư mục gốc, tạo thư mục mới và đặt tên là routes. Trong thư mục này, tạo&nbsp;<strong>userRoutes.js</strong>&nbsp;và thêm code sau:</p>

<pre id="pre10">
<code>const express = require(&#039;express&#039;);
const router = express.Router();
const userControllers = require(&#039;../controllers/userController&#039;);
const { verifyToken } = require(&#039;../middleware/auth&#039;);

router.post(&#039;/api/register&#039;, userControllers.registerUser);
router.post(&#039;/api/login&#039;, userControllers.loginUser);

router.get(&#039;/api/users&#039;, verifyToken(&#039;admin&#039;), userControllers.getUsers);

module.exports = router;</code></pre>

<p style="text-align: justify;">Code này xác định các route HTTP cho REST API. Cụ thể, route&nbsp;<strong>users</strong>&nbsp;hoạt động như route được bảo vệ. Bằng cách hạn chế truy cập tới người dùng với vai trò&nbsp;<strong>admin</strong>, bạn thực thi hiệu quả quyền truy cập dựa trên vai trò.</p>

<h2 style="text-align: justify;">Update file server chính</h2>

<p style="text-align: justify;">Mở file&nbsp;<strong>server.js</strong>&nbsp;và update nó như sau:</p>

<pre id="pre11">
<code>const express = require(&#039;express&#039;);
const cors = require(&#039;cors&#039;);
const cookieParser = require(&#039;cookie-parser&#039;);
const app = express();
const port = 5000;
require(&#039;dotenv&#039;).config();
const connectDB = require(&#039;./utils/db&#039;);
const passport = require(&#039;passport&#039;);
require(&#039;./middleware/passport&#039;)(passport);

connectDB();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use(cookieParser());
app.use(passport.initialize());

const userRoutes = require(&#039;./routes/userRoutes&#039;);
app.use(&#039;/&#039;, userRoutes);

app.listen(port, () =&gt; {
  console.log(`Server is running on port ${port}`);
});</code></pre>

<div style="text-align: justify;"><iframe allow="attribution-reporting" allowtransparency="true" browsingtopics="true" data-google-container-id="a!5" data-google-query-id="CMnHzdLJq4ADFc5rDwIdLf4CFQ" data-load-complete="true" frameborder="0" height="0" hspace="0" id="aswift_4" marginheight="0" marginwidth="0" name="aswift_4" sandbox="allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-top-navigation-by-user-activation" scrolling="no" vspace="0" width="694"></iframe></div>

<p style="text-align: justify;">Cuối cùng, khởi động server lập trình để chạy ứng dụng này.</p>

<pre id="pre12">
<code>node server.js</code></pre>

<p style="text-align: justify;">Thực hiện kiểm soát quyền truy cập dựa trên vai trò là cách hiệu quả để nâng cao bảo mật ứng dụng. Hi vọng bài viết giúp bạn thực hiện công việc này dễ dàng hơn</p>

<div style="text-align: justify;">&nbsp;</div>
		</div>
				<div id="author">
						<p>
				<strong>Nguồn tin:</strong>
				Quantrimang.com
			</p>
		</div>
	</div>
	<div id="footer" class="clearfix">
		<div id="url">
			<strong>URL của bản tin này: </strong><a href="https://www.nguoicodonvn2008.info/vi/news/savefile/kien-thuc-may-tinh/cach-trien-khai-kiem-soat-quyen-truy-cap-theo-vai-tro-trong-api-express-js-rest-bang-passport-js-va-jwt-7333.html" title="Cách triển khai kiểm soát quyền truy cập theo vai trò trong API Express.js REST bằng Passport.js và JWT">https://www.nguoicodonvn2008.info/vi/news/savefile/kien-thuc-may-tinh/cach-trien-khai-kiem-soat-quyen-truy-cap-theo-vai-tro-trong-api-express-js-rest-bang-passport-js-va-jwt-7333.html</a>

		</div>
		<div class="clear"></div>
		<div class="copyright">
			&copy; .&#x3A; Nguoicodonvn2008.info - Cõi lòng người cô đơn &#x3A;.
		</div>
		<div id="contact">
			<a href="mailto:admin@nguoicodonvn2008.info">admin@nguoicodonvn2008.info</a>
		</div>
	</div>
</div>
        <div id="timeoutsess" class="chromeframe">
            Bạn đã không sử dụng Site, <a onclick="timeoutsesscancel();" href="https://nguoicodonvn2008.info/#">Bấm vào đây để duy trì trạng thái đăng nhập</a>. Thời gian chờ: <span id="secField"> 60 </span> giây
        </div>
        <div id="openidResult" class="nv-alert" style="display:none"></div>
        <div id="openidBt" data-result="" data-redirect=""></div>
		</script>
		<div class="car-top">
  <span><img src="https://nguoicodonvn2008.info/themes/default/images/car.png" alt=""></span>
</div>
<script src="https://nguoicodonvn2008.info/assets/js/jquery/jquery.min.js"></script>
<script>var nv_base_siteurl="/",nv_lang_data="vi",nv_lang_interface="vi",nv_name_variable="nv",nv_fc_variable="op",nv_lang_variable="language",nv_module_name="news",nv_func_name="savefile",nv_is_user=0, nv_my_ofs=-4,nv_my_abbr="EDT",nv_cookie_prefix="nv4c_e856T",nv_check_pass_mstime=1738000,nv_area_admin=0,nv_safemode=0,theme_responsive=0,nv_recaptcha_ver=2,nv_recaptcha_sitekey="",nv_recaptcha_type="image",XSSsanitize=1;</script>
<script src="https://nguoicodonvn2008.info/assets/js/language/vi.js"></script>
<script src="https://nguoicodonvn2008.info/assets/js/DOMPurify/purify3.js"></script>
<script src="https://nguoicodonvn2008.info/assets/js/global.js"></script>
<script src="https://nguoicodonvn2008.info/assets/js/site.js"></script>
<script src="https://nguoicodonvn2008.info/themes/default/js/news.js"></script>
<script src="https://nguoicodonvn2008.info/themes/default/js/main.js"></script>
<script src="https://nguoicodonvn2008.info/themes/default/js/custom.js"></script>
<script type="application/ld+json">
        {
            "@context": "https://schema.org",
            "@type": "Organization",
            "url": "https://nguoicodonvn2008.info",
            "logo": "https://nguoicodonvn2008.info/uploads/angel.gif"
        }
        </script>
<script src="https://nguoicodonvn2008.info/themes/default/js/bootstrap.min.js"></script>
<script type="text/javascript">
var $scrolltop = $('.car-top');
$scrolltop.on('click', function () {
    $('html,body').animate({
        scrollTop: 0
    }, 800);
    $(this).addClass("car-run");
    setTimeout(function(){ $scrolltop.removeClass('car-run');}, 1000);
    return false;
});
$(window).on('scroll', function ()
{ 
    if($(window).scrollTop() >= 200)
    {
        $scrolltop.addClass("show");
        $scrolltop.addClass("car-down");
    }
    else
    {
       $scrolltop.removeClass("show");
       setTimeout(function(){ $scrolltop.removeClass('car-down');}, 300);
    }
});
</script>
</body>
</html>