Báo cáo đồ án cho đề tài Xây dựng website quản lý đồ án cho Khoa An toàn thông tin Học viện kỹ thuật mật mã. Đề tài lập trình và có tích hợp một số tính năng an toàn cho hệ thống. Báo cáo đạt 8.2 điểm.
BAN CƠ YẾU CHÍNH PHỦ HỌC VIỆN KỸ THUẬT MẬT Mà ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ ĐỒ ÁN TỐT NGHIỆP XÂY DỰNG WEBSITE QUẢN LÝ ĐỒ ÁN CHO KHOA AN TỒN THƠNG TIN Ngành: An tồn thơng tin Mã số: 7.48.02.02 Sinh viên thực hiện: Nghiêm Đình Giang Lớp: Người hướng dẫn: ThS Dương Xuân Hiệp Hà Nội, 2023 BAN CƠ YẾU CHÍNH PHỦ HỌC VIỆN KỸ THUẬT MẬT Mà ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ ĐỒ ÁN TỐT NGHIỆP XÂY DỰNG WEBSITE QUẢN LÝ ĐỒ ÁN CHO KHOA AN TỒN THƠNG TIN Ngành: An tồn thơng tin Mã số: 7.48.02.02 Sinh viên thực hiện: Nghiêm Đình Giang Lớp: AT14D Người hướng dẫn: ThS Dương Xuân Hiệp Hà Nội, 2023 LỜI CẢM ƠN Đầu tiên, xin gửi lời cảm ơn chân thành tới thầy cô học viện Kỹ thuật Mật Mã nói chung thầy cô hệ quản lý sinh viên khoa an tồn thơng tin nói riêng tận tình giảng dạy, truyền đạt cho kiến thức kinh nghiệm quý báu suốt thời gian sinh viên học viện, quan tâm tạo điều kiện thuận lợi cho tơi q trình thực đồ án Và để hoàn thành Đồ án tốt nghiệp này, xin gửi lời cảm ơn chân thành biết ơn sâu sắc tới giảng viên hướng dẫn ThS Dương Xuân Hiệp, người thầy tận tình giúp đỡ, trực tiếp dạy, hướng dẫn suốt trình làm đồ án tốt nghiệp Trong thời gian làm việc với thầy, không tiếp thu kiến thức chun mơn mà tơi cịn học hỏi tinh thần trách nhiệm, thái độ làm việc nghiêm túc, hiệu từ thầy Sau xin gửi lời cảm ơn chân thành tới gia đình, bạn bè động viên, đóng góp ý kiến giúp đỡ tơi q trình học tập, nghiên cứu hồn thành đồ án tốt nghiệp Tôi xin chân thành cảm ơn! Hà Nội, ngày 27 tháng 06 năm 2023 Sinh viên thực Nghiêm Đình Giang i LỜI CAM ĐOAN Tôi xin cam đoan đồ án tự nghiên cứu hướng dẫn giảng viên hướng dẫn ThS Dương Xuân Hiệp Để hoàn thành đồ án này, sử dụng tài liệu ghi mục tài liệu tham khảo, ngồi khơng sử dụng tài liệu khác mà không ghi Nếu sai, tơi xin chịu hình thức kỷ luật theo quy định Học viện Hà Nội, ngày 27 tháng 06 năm 2023 Sinh viên thực Nghiêm Đình Giang ii MỤC LỤC LỜI CẢM ƠN i LỜI CAM ĐOAN ii MỤC LỤC iii DANH MỤC KÝ HIỆU, CHỮ VIẾT TẮT vi DANH MỤC HÌNH VẼ vii DANH MỤC BẢNG BIỂU vii MỞ ĐẦU x CHƯƠNG TỔNG QUAN VỀ HỆ THỐNG QUẢN LÝ ĐỒ ÁN 1.1 Khảo sát 1.2 Phân tích tốn 1.3 Các yêu cầu chức hệ thống 1.3.1 Chức quản lý đề tài 1.3.2 Chức quản lý đề xuất đề tài 1.3.3 Chức quản lý người dùng 1.3.4 Chức quản lý sinh viên 1.3.5 Chức quản lý giảng viên quản lý 1.3.6 Chức quản lý giảng viên phản biện 1.3.7 Chức quản lý hội đồng bảo vệ 1.4 Các yêu cầu an toàn hệ thống 1.4.1 Xác thực 1.4.2 Phân quyền 1.4.3 Lọc liệu đầu vào chống số công phổ biến 1.4.4 Mã hoá liệu nhạy cảm 1.4.5 Xử lý lỗi 1.4.6 Kiểm toán 1.5 Tìm hiểu ngơn ngữ lập trình sử dụng 1.5.1 Hệ quản trị sở liệu MySQL 1.5.2 NestJS 1.5.3 Angular iii CHƯƠNG PHÂN TÍCH, THIẾT KẾ HỆ THỐNG QUẢN LÝ ĐỒ ÁN 2.1 Các chức hệ thống 2.1.1 Chức quản lý người dùng 2.1.2 Chức quản lý sinh viên 2.1.3 Chức quản lý đề tài 10 2.1.4 Chức quản lý đề xuất đề tài 10 2.1.5 Chức quản lý giảng viên quản lý 10 2.1.6 Chức quản lý giảng viên phản biện 11 2.1.7 Chức hội đồng bảo vệ 11 2.1.8 Chức quản lý tài khoản cá nhân 11 2.2 Biểu đồ use case 12 2.2.1 Các tác nhân hệ thống 12 2.2.2 Biểu đồ use case tổng quát 12 2.2.3 Biểu đồ use case quản lý đề tài 13 2.2.4 Biểu đồ use case quản lý đề xuất đề tài 14 2.2.5 Biểu đồ use case quản lý người dùng 15 2.2.6 Biểu đồ use case quản lý sinh viên 16 2.2.7 Biểu đồ use case quản lý giảng viên quản lý 17 2.2.8 Biểu đồ use case quản lý giảng viên phản biện 18 2.2.9 Biểu đồ use case quản lý hội đồng bảo vệ 19 2.3 Biểu đồ hoạt động 20 2.3.1 Biểu đồ hoạt động chức đăng nhập 20 2.3.2 Biểu đồ hoạt động chức đăng xuất 21 2.3.3 Biểu đồ hoạt động chức phê duyệt đề tài 22 2.3.4 Biểu đồ hoạt động chức thành lập danh sách hội đồng 23 2.4 Cơ chế an toàn 24 2.4.1 Cơ chế xác thực 24 2.4.2 Cơ chế xác thực hai yếu tố 25 2.4.3 Cơ chế phân quyền 27 2.4.4 Cơ chế lọc liệu đầu vào chống số công phổ biến 27 iv 2.4.5 Cơ chế mã hoá liệu nhạy cảm 28 2.4.6 Cơ chế xử lý lỗi 29 2.4.7 Cơ chế kiểm toán 30 2.5 Thiết kế sở liệu 30 CHƯƠNG XÂY DỰNG HỆ THỐNG QUẢN LÝ ĐỒ ÁN 37 3.1 Xây dựng sở liệu 37 3.2 Xây dựng chức 38 3.2.1 Chức đăng nhập xác thực hai yếu tố 38 3.2.2 Chức quản lý đề tài 40 3.2.3 Chức quản lý đề xuất đề tài 47 3.2.4 Chức quản lý người dùng 48 3.2.5 Chức quản lý sinh viên 51 3.2.6 Chức quản lý giảng viên quản lý 53 3.2.7 Chức quản lý giảng viên phản biện 55 3.2.8 Chức quản lý hội đồng bảo vệ 57 3.2.9 Chức quản lý tài khoản cá nhân 59 3.2.10 Chức xem thống kê 61 3.3 Đánh giá số tính an tồn hệ thống 62 3.3.1 Xác thực hai yếu tố 62 3.3.2 Xác thực phân quyền 62 3.3.3 Giới hạn lưu lượng truy cập 64 3.3.4 Chống số công phổ biến 65 KẾT LUẬN 67 TÀI LIỆU THAM KHẢO 68 PHỤ LỤC 69 v DANH MỤC KÝ HIỆU, CHỮ VIẾT TẮT STT Từ viết tắt Thuật ngữ đầy đủ/ Giải thích API Application Programming Interface CSDL Cơ sở liệu ERD HTTP JSON JavaScript Object Notation JWT JSON Web Token OTP One Time Password (Mật dùng lần) SQL URI Uniform Resource Identifier 10 XSS Cross-site Scripting (Tấn công script liên miền) 11 2FA Two Factor Authentication (Xác thực hai bước) Entity Relationship Diagram (Biểu đồ quan hệ thực thể) HyperText Transfer Protocol (Giao thức truyền siêu văn bản) Structured Query Language (Ngơn ngữ truy vấn có cấu trúc) vi DANH MỤC HÌNH VẼ Hình 2.1 Biểu đồ phân rã chức hệ thống Hình 2.2 Biểu đồ phân rã chức quản lý người dùng Hình 2.3 Biểu đồ phân rã chức quản lý sinh viên Hình 2.4 Biểu đồ phân rã chức quản lý đề tài 10 Hình 2.5 Biểu đồ phân rã chức quản lý đề xuất đề tài 10 Hình 2.6 Biểu đồ phân rã chức quản lý giảng viên quản lý 10 Hình 2.7 Biểu đồ phân rã chức quản lý giảng viên phản biện 11 Hình 2.8 Biểu đồ phân rã chức quản lý hội đồng bảo vệ 11 Hình 2.9 Biểu đồ phân rã chức quản lý tài khoản cá nhân 11 Hình 2.10 Biểu đồ use case tổng quát 12 Hình 2.11 Biểu đồ use case quản lý đề tài 13 Hình 2.12 Biểu đồ use case quản lý đề xuất đề tài 14 Hình 2.13 Biểu đồ use case quản lý người dùng 15 Hình 2.14 Biểu đồ use case quản lý sinh viên 16 Hình 2.15 Biểu đồ use case quản lý giảng viên quản lý 17 Hình 2.16 Biểu đồ use case quản lý giảng viên phản biện 18 Hình 2.17 Biểu đồ use case quản lý hội đồng bảo vệ 19 Hình 2.18 Biểu đồ hoạt động chức đăng nhập 20 Hình 2.20 Biểu đồ hoạt động chức đăng xuất 21 Hình 2.21 Biểu đồ hoạt động chức phê duyệt đề tài 22 Hình 2.22 Biểu đồ hoạt động chức thành lập danh sách hội đồng 23 Hình 2.23 Biểu đồ luồng xác thực JWT 25 Hình 2.24 Sơ đồ q trình kích hoạt xác thực hai bước thông qua ứng dụng Authentication 26 Hình 2.25 Sơ đồ trình băm mật 28 Hình 2.26 Sơ đồ q trình mã hố/ giải mã AES 29 Hình 3.1 Sơ đồ ERD 37 Hình 3.2 Giao diện chức đăng nhập 38 Hình 3.3 Giao diện chức xác thực thơng qua ứng dụng 39 Hình 3.4 Giao diện chức xác thực thông qua email 39 Hình 3.5 Giao diện danh sách đề tài 40 Hình 3.6 Giao diện thêm mới/ chỉnh sửa thơng tin đề tài 41 Hình 3.7 Giao diện đề xuất đề tài 41 Hình 3.8 Giao diện xố đề tài 42 Hình 3.9 Giao diện nhập đề tài từ file Excel 42 Hình 3.10 Giao diện báo cáo tiến độ 43 Hình 3.11 Giao diện giảng viên hướng dẫn nhận xét 44 Hình 3.12 Giao diện giảng viên phản biện nhận xét 44 vii Hình 3.13 Giao diện hội đồng chấm điểm 45 Hình 3.14 Giao diện chi tiết đề tài 46 Hình 3.15 Giao diện danh sách đề xuất đề tài 47 Hình 3.16 Giao diện phê duyệt đề tài 47 Hình 3.17 Giao diện từ chối đề tài 48 Hình 3.18 Giao diện danh sách người dùng 48 Hình 3.19 Giao diện thêm mới/ chỉnh sửa thông tin người dùng 49 Hình 3.20 Giao diện chức nhập ngườ dùng từ file Excel 49 Hình 3.21 Giao diện kích hoạt/ huỷ kích hoạt người dùng 50 Hình 3.22 Giao diện chi tiết người dùng 50 Hình 3.23 Giao diện danh sách sinh viên 51 Hình 3.24 Giao diện thêm mới/ chỉnh sửa thông tin sinh viên 51 Hình 3.25 Giao diện nhập sinh viên từ file Excel 52 Hình 3.26 Giao diện xoá sinh viên 52 Hình 3.27 Giao diện danh sách giảng viên quản lý 53 Hình 3.28 Giao diện thêm mới/ chỉnh sửa nhóm quản lý 53 Hình 3.29 Giao diện thành lập danh sách nhóm quản lý (1) 54 Hình 3.30 Giao diện thành lập danh sách quản lý (2) 54 Hình 3.31 Giao diện danh sách giảng viên phản biện 55 Hình 3.32 Giao diện thêm mới/ chỉnh sửa nhóm phản biện 55 Hình 3.33 Giao diện thành lập danh sách nhóm phản biện (1) 56 Hình 3.34 Giao diện thành lập danh sách nhóm phản biện (2) 57 Hình 3.35 Giao diện danh sách hội đồng 57 Hình 3.36 Giao diện thêm mới/ chỉnh sửa hội đồng 58 Hình 3.37 Giao diện thành lập danh sách hội đồng (1) 58 Hình 3.38 Giao diện thành lập danh sách hội đồng (2) 59 Hình 3.39 Giao diện quản lý tài khoản cá nhân 59 Hình 3.40 Giao diện thay đổi Email cá nhân 60 Hình 3.41 Giao diện thay đổi mật 60 Hình 3.42 Giao diện thay đổi phương thức xác thực 61 Hình 3.43 Giao diện xem thống kê tổng quan 61 Hình 3.44 Giao diện thơng báo khố đăng nhập thiết bị 62 Hình 3.45 API thơng báo chuỗi JWT không hợp lệ 63 Hình 3.46 Giao diện thơng báo người dùng khơng có quyền truy cập 63 Hình 3.47 API thơng báo người dùng khơng có quyền truy cập 64 Hình 3.48 API thơng báo lỗi giới hạn lưu lượng truy cập 65 Hình 3.49 API thơng báo lỗi liệu đầu vào không hợp lệ 66 Hình 3.50 Giao diện hiển thị liệu chứa script 66 viii Hình 3.42 Giao diện thay đổi phương thức xác thực 3.2.10 Chức xem thống kê Chức cho phép quản trị viên quan sát tổng quan số đề tài hệ thống, phổ điểm thống kê dựa thang điểm giảng viên hướng dẫn, giảng viên phản biện hội đồng đánh giá Ngoài ra, quản trị viên xem thống kê theo khoa học kỳ cụ thể Hình 3.43 Giao diện xem thống kê tổng quan 61 3.3 Đánh giá số tính an tồn hệ thống 3.3.1 Xác thực hai yếu tố Tính xác thực hai bước đóng vai trị quan trọng việc ngăn chặn công từ điển sử dụng mã xác thực bị đánh cắp Bằng cách giới hạn số lần nhập sai mã xác thực, hệ thống đảm bảo người dùng khơng thể đốn mã xác thực khơng có khả lợi dụng mã sử dụng trước Nếu người dùng nhập sai mã số lần cho phép, hệ thống khoá thiết bị đăng nhập tài khoản 30 phút, việc cung cấp khoảng thời gian đủ dài để người dùng hệ thống phát phản ứng hoạt động xâm nhập Hình 3.44 Giao diện thơng báo khố đăng nhập thiết bị 3.3.2 Xác thực phân quyền Sau đăng nhập thành công, hệ thống cung cấp cho người dùng chuỗi JWT để xác thực phân quyền Với yêu cầu tới hệ thống, trình duyệt đính kèm chuỗi JWT vào yêu cầu Nếu chuỗi JWT hợp lệ, hệ thống xử lý trả thông tin mà người dùng yêu cầu Ngược lại, hệ thống trả lỗi yêu cầu người dùng đăng nhập Điều góp phần ngăn chặn công giả mạo nhắm tới hệ thống Ngồi ra, JWT chứa thơng tin xác thực, hệ thống không cần phải truy vấn sở liệu phiên để xác minh thông tin người dùng, giảm thiểu tải cho máy chủ cải thiện hiệu ứng dụng 62 Hình 3.45 API thơng báo chuỗi JWT khơng hợp lệ Để kiểm sốt quyền truy cập hệ thống, client server thực việc kiểm tra quyền tương ướng với tài khoản người dùng Dựa vào thông tin người dùng chứa chuỗi JWT, hệ thống kiểm tra người dùng có quyền u cầu chức khơng, khơng, hệ thống trả thông báo lỗi cho người dùng Việc giúp bảo vệ hệ thống khỏi việc truy cập trái phép lạm dụng tài nguyên Hình 3.46 Giao diện thơng báo người dùng khơng có quyền truy cập 63 Hình 3.47 API thơng báo người dùng khơng có quyền truy cập 3.3.3 Giới hạn lưu lượng truy cập Hệ thống giới hạn lưu lượng truy cập từ địa IP người dùng cụ thể khoảng thời gian định Điều giúp hạn chế công từ chối dịch vụ (Dos) đảm bảo tính ổn định cho hệ thống 64 Hình 3.48 API thơng báo lỗi giới hạn lưu lượng truy cập 3.3.4 Chống số công phổ biến Hệ thống kiểm tra tất liệu đầu vào yêu cầu Nếu liệu không hợp lệ, hệ thống trả lỗi cho người dùng Điều giúp hệ thống tránh công SQL Injection người dùng cố tình gửi lên chuỗi ký tự chứa câu truy vấn 65 Hình 3.49 API thơng báo lỗi liệu đầu vào khơng hợp lệ Ngồi việc hiển thị liệu cho người dùng thao tác (được trả từ máy chủ hệ thống) lọc qua hàm Sanitization (một hàm tiện ích thư viện Angular) để biến thành chuỗi liệu an tồn, tất thẻ html, script liệu in dạng chuỗi, khơng đính kèm thêm vào file html tại, nên lớp bảo vệ người dùng trước nỗ lực công XSS Hình 3.50 Giao diện hiển thị liệu chứa script 66 KẾT LUẬN Qua vấn đề trình bày đồ án, thấy việc tin học hóa q trình quản lý đem lại lợi ích to lớn Nó giúp cho cơng việc quản lý đồ án tốt nghiệp sinh viên dễ dàng hơn, giảm thiểu mát hỏng liệu q trình quản lý Trong khn khổ đồ án, thời gian nghiên cứu không nhiều nên kết đạt chưa cao Hệ thống giải cơng việc sau: - Tìm hiểu toán quản lý đồ án tốt nghiệp sinh viên - Lập bảng phân tích thiết kế hệ thống quản lý đồ án tốt nghiệp sinh viên Học viện Kỹ thuật mật mã - Xây dựng phần mềm quản lý đồ án tốt nghiệp sinh viên Học viện Phần mềm bao gồm chức năng: Quản lý đề tài, Quản lý đề xuất đề tài, Quản lý giảng viên quản lý, Quản lý giảng viên phản biện, Quản lý hội đồng bảo vệ, Hệ thống đáp ứng số yêu cầu quản lý đồ án tốt nghiệp sinh viên Học viện Việc thực đề tài giúp em trau dồi lại kiến thức học, đồng thời tìm hiểu nghiên cứu kiến thức để ứng dụng vào việc phát triển hệ thống thông tin Những hạn chế hệ thống Do thời gian thực đồ án tương đối hạn chế trình độ hiểu biết cơng cụ ngơn ngữ lập trình sử dụng chúng em cịn nơng cạn nên chưa khai thác hết mạnh hệ quản trị sở liệu MySQL nên chương trình mang lại hiệu chưa cao Hệ thống cịn chưa hồn chỉnh chưa tối ưu sở liệu tích hợp thêm nhiều chế an tồn cho hệ thống Và hướng phát triển sau đề tài 67 TÀI LIỆU THAM KHẢO [1] TS Nguyễn Tuấn Anh, KS Dương Xuân Hiệp (2013), Xây dựng ứng dụng web an toàn, Học viện Kỹ thuật Mật Mã, Hà Nội [2] OWASP (2005), A guide to building secure web applications and web service [3] TS Nguyễn Thị Thanh Xuân (2013), Giáo trình thiết kế Web, Cao đẳng nghề Công Nghiệp Hà Nội, Hà Nội [4] Express Team (2017), Security Best Practices for Express in Production, Express https://expressjs.com/en/advanced/best-practicesecurity.html [5] Wikipedia contributors (2022), Bcrypt, Wikipedia https://en.wikipedia.org/wiki/Bcrypt [6] Tùng Đ (2021), NodeJS gì? Tại NodeJS lại quan trọng với lập trình web?, Cơng ty Cổ phần Tino Group https://wiki.tino.org/nodejs-la-gi/ [7] NestJS Documentation [8] Angular Documentation 68 PHỤ LỤC Đoạn mã mã hoá/ giải mã AES: const IV_LENGTH = 16; // Với AES, IV thường gồm 16 ký tự export function encrypt(text: string, encryptionKey: string){ const iv = Buffer.from(randomBytes(IV_LENGTH)) toString('hex') slice(0, IV_LENGTH); const cipher = createCipheriv('aes-256-cbc', Buffer.from(encryptionKey), iv); let encrypted = cipher.update(text); encrypted = Buffer.concat([encrypted, cipher.final()]); return iv + ':' + encrypted.toString('hex'); } export function decrypt(text: string, encryptionKey: string){ const textParts: string[] = text.includes(':') ? text.split(':') : []; const iv = Buffer.from(textParts.shift() || '', 'binary'); const encryptedText = Buffer.from(textParts.join(':'), 'hex'); const decipher = createDecipheriv( 'aes-256-cbc', Buffer.from(encryptionKey), iv, ); let decrypted = decipher.update(encryptedText); decrypted = Buffer.concat([decrypted, decipher.final()]); return decrypted.toString(); } Đoạn mã kiểm tra xác thực tài khoản đăng nhập hệ thống: async login(userLoginDto: UserLoginDto): Promise { const user = await this.userService.findByEmail(userLoginDto.email); if (!user) { throw new NotFoundException('Tài khoản mật khơng xác!'); } const isPasswordMatch = await validateHash( userLoginDto.password, user.password, ); if (!isPasswordMatch) { 69 throw new NotFoundException('Tài khoản mật khơng xác!'); } if (!user.isActive) { throw new ForbiddenException( 'Tài khoản bạn bị khố! Vui lịng liên hệ Quản trị viên để xử lý.', ); } const session = await this.userSessionService.find( userLoginDto.deviceId, user.id, ); if (session?.isTrusted) { return this.getTokenAndSaveSession(user, { deviceId: userLoginDto.deviceId, deviceName: userLoginDto.deviceName, ipAddress: userLoginDto.ipAddress, isTrusted: true, }); } switch (user.twoFactory) { case TwoFactoryMethod.EMAIL: const otp = await this.otpService.generateEmailOtp( userLoginDto.deviceId, user.email, ); await this.emailQueueService.add( TFA_VERIFY_PROCESS, { otp, email: user.email, requestDate: moment().format('DD/MM/YYYY HH:mm'), deviceName: userLoginDto.deviceName, }, { removeOnComplete: true }, ); return new TokenPayloadDto({ twoFactoryMethod: user.twoFactory, }); case TwoFactoryMethod.OTP: return new TokenPayloadDto({ twoFactoryMethod: user.twoFactory, requiredOtpToken: isEmpty(user.optSecret), }); default: return this.getTokenAndSaveSession(user, { 70 deviceId: userLoginDto.deviceId, deviceName: userLoginDto.deviceName, ipAddress: userLoginDto.ipAddress, isTrusted: false, }); } } Đoạn mã kiểm tra mã xác thực: private async verify( userEmail: string, deviceId: string, verifyFn: () => boolean, ) { let failedCount = +( (await this.cacheService.get(`${userEmail}_${deviceId}_2fa_failed`)) || ); const maxVerifyFailed = this.apiConfigService.otpConfig.maxVerifyFailed; const blockTime = this.apiConfigService.otpConfig.blockVerifyFailedTime; if (failedCount >= maxVerifyFailed) { throw new OtpInvalidException( 'Mã xác thực không hợp lệ Bạn đăng nhập thiết bị ${ blockTime / 60 } phút.', ); } const isValid = verifyFn(); if (!isValid) { failedCount++; await this.cacheService.set( ${userEmail}_${deviceId}_2fa_failed, failedCount, blockTime * 1000, ); throw new OtpInvalidException( failedCount >= maxVerifyFailed ? 'Mã xác thực không hợp lệ Bạn đăng nhập thiết bị ${ blockTime / 60 } phút' : 'Mã xác thực khơng hợp lệ Bạn cịn ${ maxVerifyFailed - failedCount } lần thử.', ); 71 } else { await this.cacheService.del(`${userEmail}_${deviceId}_2fa_failed`); } return isValid; } Đoạn mã kiểm tra phân quyền cho yêu cầu đến hệ thống: export class RolesGuard implements CanActivate { constructor(private readonly reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const role = this.reflector.get( 'role', context.getHandler(), ); const request = context.switchToHttp().getRequest(); const user = request.user; if (!role) { return true; } const roles = Array.isArray(role) ? role : [role]; return roles.includes(user.role); } } Đoạn mã tải tệp đính kèm lên Google Driver: async uploadFile(fileObject: any, folderId: string, isPublic = true) { try { const bufferStream = new stream.PassThrough(); bufferStream.end(fileObject.buffer); const { data } = await this.driver.files.create({ media: { mimeType: fileObject.mimeType, body: bufferStream, }, requestBody: { name: fileObject.originalname, parents: folderId ? [folderId] : [], }, fields: 'id,name', }); const { webViewLink, webContentLink } = await this.getFile(data.id); isPublic && (await this.setFilePublic(data.id)); return { data, webViewLink, webContentLink }; } catch (e) { throw e; } 72 } Đoạn mã cập nhật báo cáo tiến độ: async report( id: number, request: { type: ProjectProgressType }, files: { wordFile; reportFile; otherFile }, user: UserEntity, ) { const project = await this.projectRepository.findOne({ where: { id }, }); if (!project) { throw new NotFoundException('Đề tài không tồn tại'); } const progress = await this.projectProgressRepository.findOne({ where: { projectId: project.id, type: request.type }, }); let folderId; const uploadedFile: { [key: string]: string } = {}; try { if (progress) { folderId = progress.folderId; } else { const { id } = await this.driverService.createFolder( ProjectProgress[request.type], project.folderId, ); folderId = id; } for (const key of Object.keys(files)) { if (!files[key] || !files[key].length) { continue; } const data = await this.driverService.uploadFile( files[key][0], folderId, ); uploadedFile[key] = JSON.stringify({ id: data.id, name: data.name, webViewLink: data.webViewLink, webContentLink: data.webContentLink, }); } } catch (e) { throw new BadRequestException('Có lỗi xảy ra! Vui lòng thử lại sau'); 73 } if (!progress) { // Ghi nhật ký hoạt động const event: UserEventDto = { message: 'Cập nhật ${ ProjectProgress[request.type] } cho đề tài {projectName}', params: JSON.stringify({ projectName: project.name, projectId: project.id, }), userId: user.id, }; this.userEventService.insert(event).then(); return this.projectProgressRepository.insert({ folderId, uploadedFile, projectId: project.id, type: request.type, }); } return await this.projectProgressRepository.update( { id: progress.id }, uploadedFile, ); } Đoạn mã kiểm tra liệu đầu vào thêm mới/ chỉnh sửa người dùng: export class UserRequestDto { @StringProperty('Họ tên', { required: true, trim: true, }) readonly fullName: string; @StringProperty('Email', { required: true, trim: true, isEmail: true, }) readonly email: string; @StringProperty('Số điện thoại', { trim: true, }) readonly phone?: string; @StringProperty('Địa chỉ', { trim: true, }) 74 readonly address?: string; @EnumProperty('Giới tính', Gender) readonly gender?: Gender; @DateProperty('Ngày sinh') readonly birthday?: Date; @EnumProperty('Vai trò', Role, { default: Role.LECTURER }) role: Role; @StringProperty('Đơn vị', { trim: true, }) readonly workPlace?: string; password?: string; } 75