1. JWT và Token Authentication là gì?

Trong quá trình phát triển Website, Mobile App và REST API, hệ thống cần có cách nhận biết người dùng sau khi họ đăng nhập thành công. Nếu mỗi lần thực hiện một thao tác, người dùng đều phải nhập lại email và mật khẩu thì sẽ rất bất tiện. Vì vậy, Token Authentication được sử dụng để giúp hệ thống duy trì việc xác thực trong những Request tiếp theo.

Token Authentication là phương thức xác thực sử dụng một chuỗi dữ liệu gọi là Token để xác minh hoặc thể hiện trạng thái xác thực của người dùng. Sau khi đăng nhập thành công, hệ thống cấp Token cho Client. Khi cần truy cập những API được bảo vệ, Client gửi Token kèm theo Request để Backend kiểm tra trước khi xử lý.

JWT là một định dạng Token phổ biến, cho phép truyền tải thông tin dưới dạng JSON giữa các bên. JWT thường được sử dụng trong các hệ thống đăng nhập, xác thực API và trao đổi thông tin giữa những dịch vụ. Token có thể chứa thông tin như mã người dùng, vai trò hoặc thời điểm hết hạn, tùy theo cách thiết kế của hệ thống.

JWT và Token Authentication có mối liên hệ với nhau nhưng không phải là một. Token Authentication là phương thức sử dụng Token để xác thực, còn JWT là một định dạng Token có thể được sử dụng trong phương thức đó. Không phải Token nào cũng là JWT, và hệ thống sử dụng Token Authentication cũng có thể dùng những định dạng Token khác.

Ví dụ, khi đăng nhập vào một ứng dụng mạng xã hội, người dùng nhập email và mật khẩu. Backend kiểm tra thông tin, nếu hợp lệ thì cấp Access Token. Khi người dùng muốn xem bảng tin hoặc gửi tin nhắn, ứng dụng gửi Token kèm theo Request. Backend kiểm tra Token, xác định người dùng và tiếp tục kiểm tra quyền truy cập trước khi xử lý yêu cầu.

Nói đơn giản, Token giúp hệ thống nhận diện hoặc xác minh những Request tiếp theo mà không cần yêu cầu người dùng nhập lại mật khẩu mỗi lần sử dụng ứng dụng.

2. Token Authentication hoạt động như thế nào?

2.1. Quy trình xác thực bằng Token

Quá trình Token Authentication thường diễn ra theo các bước sau:

Bước 1: Người dùng đăng nhập

Người dùng nhập email và mật khẩu trên giao diện ứng dụng. Frontend gửi thông tin đến API đăng nhập của Backend thông qua kết nối HTTPS.

Bước 2: Backend kiểm tra thông tin

Backend kiểm tra tài khoản trong cơ sở dữ liệu và đối chiếu mật khẩu với thông tin đã lưu. Nếu thông tin không hợp lệ, hệ thống từ chối đăng nhập. Nếu thông tin chính xác, hệ thống tiếp tục thực hiện bước xác thực tiếp theo.

Bước 3: Backend cấp Token

Sau khi xác thực thành công, Backend tạo hoặc cấp Token theo cơ chế đã được thiết lập. Token có thể chứa thông tin nhận diện người dùng và thời hạn sử dụng. Sau đó, Token được gửi về Client để sử dụng trong những Request tiếp theo.

Bước 4: Client gửi Token khi gọi API

Khi người dùng truy cập một chức năng cần đăng nhập, Client gửi Request đến Backend và đính kèm Token. Một cách phổ biến là gửi Token trong HTTP Authorization Header.

Bước 5: Backend xác minh Token

Backend kiểm tra Token theo cơ chế của hệ thống. Nếu sử dụng JWT, hệ thống cần xác minh chữ ký, thời hạn và những thông tin cần thiết khác. Nếu Token hợp lệ, Backend xác định danh tính người dùng rồi kiểm tra quyền truy cập tương ứng.

Bước 6: Trả về kết quả

Nếu Token hợp lệ và người dùng có đủ quyền, API trả về dữ liệu hoặc thực hiện thao tác được yêu cầu. Nếu Token không hợp lệ, đã hết hạn hoặc người dùng không có quyền, hệ thống sẽ từ chối yêu cầu với phản hồi phù hợp.

Authentication Tokens | Two Main Types of Authentication Tokens

2.2. Ví dụ sử dụng Token trong REST API

Giả sử một ứng dụng có chức năng đăng nhập và xem thông tin cá nhân. Sau khi đăng nhập thành công, Backend trả về Access Token cho ứng dụng.

Khi người dùng muốn xem thông tin cá nhân, Frontend gửi Request đến API và đính kèm Token trong Header.

Ví dụ:

Authorization: Bearer <access_token>

Trong đó:

  • Authorization: Header dùng để truyền thông tin xác thực hoặc thông tin liên quan đến quyền truy cập.
  • Bearer: Chỉ định cơ chế sử dụng Bearer Token.
  • Access Token: Token được gửi để truy cập tài nguyên được bảo vệ.

Backend tiếp nhận Request, kiểm tra Token rồi xác định tài khoản tương ứng. Nếu Token hợp lệ và tài khoản được phép truy cập dữ liệu, hệ thống sẽ trả về thông tin cá nhân.

Nếu Token không hợp lệ hoặc đã hết hạn, API thường trả về HTTP 401 Unauthorized. Nếu người dùng đã được xác thực nhưng không có quyền thực hiện hành động, API thường trả về HTTP 403 Forbidden.

Điều cần chú ý là Token hợp lệ không đồng nghĩa người dùng được phép truy cập tất cả dữ liệu. Backend vẫn phải kiểm tra quyền hạn trước khi xử lý những thao tác cần được bảo vệ.

3. JWT 

3.1. JWT là gì?

JWT là viết tắt của JSON Web Token, một định dạng Token được sử dụng để truyền tải thông tin giữa các bên dưới dạng JSON. JWT có cấu trúc tiêu chuẩn và thường được sử dụng trong hệ thống xác thực người dùng, REST API và các ứng dụng có nhiều dịch vụ giao tiếp với nhau.

Một JWT thông thường gồm ba phần được ngăn cách bởi dấu chấm, lần lượt là Header, Payload và Signature.

Cấu trúc tổng quát:

Header.Payload.Signature

Mỗi phần đảm nhận một nhiệm vụ riêng. Header mô tả thông tin của Token, Payload chứa các thông tin cần truyền tải, còn Signature giúp bên nhận kiểm tra tính toàn vẹn của Token.

JWT thường được mã hóa theo định dạng Base64URL để tạo thành chuỗi ký tự thuận tiện cho việc truyền tải. Tuy nhiên, Base64URL chỉ là cách biểu diễn dữ liệu, không phải phương pháp mã hóa bảo mật. Nếu JWT chỉ được ký mà không được mã hóa nội dung, người có Token có thể đọc được Header và Payload.

JWT là gì? Tại sao JWT trở nên phổ biến như vậy?

3.2. Các thành phần của JWT

Header

Header chứa thông tin mô tả Token, thường bao gồm loại Token và thuật toán được sử dụng để tạo chữ ký. Một số thuật toán thường gặp là HS256 và RS256.

Thông tin này giúp hệ thống biết cách xử lý Token. Tuy nhiên, Backend cần tự quy định những thuật toán được phép sử dụng và không nên tin tưởng hoàn toàn vào thuật toán được khai báo bên trong Token.

Payload

Payload chứa các Claim, tức những thông tin được khai báo trong Token. Các Claim có thể bao gồm mã người dùng, bên phát hành Token, đối tượng nhận Token và thời điểm hết hạn.

Một số Claim phổ biến gồm:

  • sub: Định danh chủ thể, thường là người dùng.
  • iss: Bên phát hành Token.
  • aud: Đối tượng nhận Token.
  • exp: Thời điểm Token hết hạn.
  • iat: Thời điểm Token được phát hành.

Ngoài các Claim tiêu chuẩn, hệ thống có thể bổ sung Claim riêng như vai trò hoặc phạm vi truy cập. Tuy nhiên, không nên đưa mật khẩu, khóa bí mật hoặc thông tin nhạy cảm vào Payload vì nội dung này có thể đọc được nếu Token không sử dụng cơ chế mã hóa.

Signature

Signature là chữ ký được tạo từ Header, Payload và khóa tương ứng theo thuật toán được lựa chọn. Chữ ký giúp hệ thống kiểm tra Token có bị thay đổi sau khi phát hành hay không và xác minh rằng Token được tạo theo cơ chế ký hợp lệ.

Ví dụ, nếu một người tự ý thay đổi mã người dùng hoặc vai trò trong Payload, chữ ký ban đầu sẽ không còn hợp lệ với nội dung mới. Backend có thể phát hiện việc sửa đổi này khi xác minh chữ ký.

Tuy nhiên, chữ ký hợp lệ không có nghĩa mọi thông tin trong Token đều còn phù hợp với trạng thái hiện tại của hệ thống. Backend vẫn cần kiểm tra thời hạn, mục đích sử dụng và quyền truy cập trước khi xử lý Request.

3.3. JWT hoạt động như thế nào?

Khi người dùng đăng nhập thành công, Backend tạo JWT chứa những thông tin cần thiết rồi ký Token bằng khóa phù hợp. Token được trả về Client để sử dụng trong các Request tiếp theo.

Khi nhận Request, Backend kiểm tra chữ ký và thời hạn của JWT. Nếu hệ thống có cấu hình kiểm tra Issuer, Audience hoặc những Claim khác thì các điều kiện đó cũng phải được xác minh.

Nếu Token hợp lệ, Backend có thể sử dụng thông tin trong Token để nhận diện người dùng và tiếp tục kiểm tra quyền truy cập. Nếu chữ ký không hợp lệ hoặc Token đã hết hạn, hệ thống sẽ từ chối yêu cầu.

Một ưu điểm của JWT là Server có thể xác minh Token mà không nhất thiết phải truy vấn cơ sở dữ liệu để tìm Session ở mỗi Request. Điều này có thể hữu ích đối với những hệ thống có nhiều dịch vụ hoặc cần mở rộng quy mô.

Tuy nhiên, JWT không tự động giải quyết mọi vấn đề về quản lý đăng nhập. Nếu cần thu hồi Token ngay lập tức, cập nhật quyền mới nhất hoặc theo dõi trạng thái phiên đăng nhập, hệ thống có thể phải kết hợp thêm cơ sở dữ liệu hoặc những cơ chế quản lý khác.

3.4. Ví dụ về cấu trúc JWT

Một JWT thường có dạng như sau:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NSJ9.signature

Đây chỉ là chuỗi minh họa cấu trúc gồm ba phần, không phải Token đăng nhập dùng cho một hệ thống thực tế.

Khi giải mã phần Header và Payload, có thể đọc được những thông tin như thuật toán ký hoặc mã định danh người dùng. Phần Signature được sử dụng để xác minh tính toàn vẹn của Token.

Trong dự án thực tế, lập trình viên nên sử dụng thư viện JWT đáng tin cậy thay vì tự ghép chuỗi để tạo Token. Việc tạo và xác minh Token cần được triển khai theo đúng tiêu chuẩn để tránh những lỗi bảo mật.

4. Các loại Token thường gặp

4.1. Access Token

Access Token là Token được sử dụng để truy cập những tài nguyên hoặc API cần xác thực. Sau khi người dùng đăng nhập thành công, hệ thống cấp Access Token để Client gửi kèm các Request tiếp theo.

Ví dụ, khi người dùng mở trang hồ sơ cá nhân, ứng dụng gửi Access Token đến Backend. Backend kiểm tra Token, xác định người dùng và kiểm tra quyền truy cập trước khi trả về dữ liệu.

Access Token thường được thiết lập thời hạn tương đối ngắn nhằm hạn chế rủi ro nếu Token bị đánh cắp. Thời hạn cụ thể phụ thuộc vào yêu cầu bảo mật và cách triển khai của từng hệ thống.

Access Token có thể sử dụng định dạng JWT hoặc một chuỗi ngẫu nhiên được Server quản lý. Vì vậy, không nên mặc định rằng mọi Access Token đều là JWT.

4.2. Refresh Token

Refresh Token được sử dụng để yêu cầu cấp Access Token mới khi Access Token hết hạn hoặc cần được làm mới theo cơ chế của hệ thống.

Ví dụ, người dùng đăng nhập vào ứng dụng và sử dụng Access Token trong một khoảng thời gian. Khi Access Token hết hạn, ứng dụng có thể gửi Refresh Token đến API làm mới Token để nhận Access Token mới mà không cần yêu cầu người dùng nhập lại mật khẩu ngay lập tức.

Refresh Token thường có thời hạn dài hơn Access Token nên cần được bảo vệ chặt chẽ. Hệ thống có thể quản lý Refresh Token ở Server, giới hạn thời gian sử dụng, hỗ trợ thu hồi hoặc thay thế Refresh Token sau mỗi lần làm mới.

Access Token và Refresh Token có nhiệm vụ khác nhau. Access Token được dùng để truy cập API, còn Refresh Token được dùng để yêu cầu cấp Access Token mới. Không nên gửi Refresh Token đến các API nghiệp vụ thông thường.

4.3. ID Token

ID Token thường được sử dụng trong OpenID Connect, một lớp xác thực được xây dựng trên nền OAuth 2.0. Token này chứa thông tin về kết quả xác thực và danh tính người dùng để Client xử lý theo quy trình đăng nhập.

ID Token khác với Access Token về mục đích sử dụng. ID Token cung cấp thông tin xác thực danh tính cho Client, trong khi Access Token được sử dụng để truy cập tài nguyên được bảo vệ.

Việc sử dụng nhầm ID Token thay cho Access Token có thể dẫn đến lỗi xác thực hoặc lỗ hổng bảo mật nếu hệ thống không kiểm tra đúng loại Token.

5. JWT Authentication và Session-Based Authentication

JWT Authentication và Session-Based Authentication đều được sử dụng để quản lý trạng thái xác thực của người dùng, nhưng cách tổ chức dữ liệu và kiểm tra thông tin khác nhau.

Session-Based Authentication

Với Session-Based Authentication, sau khi đăng nhập thành công, Server tạo một Session và lưu thông tin phiên đăng nhập ở phía Server. Client thường lưu Session ID trong Cookie rồi gửi lại trong những Request tiếp theo.

Khi nhận Request, Server sử dụng Session ID để tìm phiên đăng nhập tương ứng. Nếu Session còn hợp lệ, hệ thống xác định được người dùng đang thực hiện yêu cầu.

Ưu điểm của phương thức này là Server có thể quản lý và thu hồi phiên đăng nhập tương đối trực tiếp. Tuy nhiên, với hệ thống có nhiều máy chủ, việc quản lý Session cần được thiết kế phù hợp để các máy chủ có thể sử dụng chung trạng thái phiên khi cần thiết.

JWT Authentication

Với JWT Authentication, Server cấp JWT sau khi xác thực thành công. Client gửi Token trong những Request tiếp theo, còn Server xác minh chữ ký và các điều kiện cần thiết để kiểm tra Token.

Nếu được thiết kế theo hướng xác minh độc lập, JWT có thể giúp giảm nhu cầu lưu và tra cứu trạng thái Session ở Server. Tuy nhiên, việc thu hồi JWT trước thời điểm hết hạn thường phức tạp hơn nếu hệ thống không lưu trạng thái hoặc có cơ chế thu hồi bổ sung.

Không có phương thức nào phù hợp với tất cả các dự án. Việc lựa chọn phụ thuộc vào kiến trúc ứng dụng, yêu cầu mở rộng, cách quản lý phiên đăng nhập và mức độ kiểm soát mà hệ thống cần.

6. JWT & Token Authentication trong REST API

Trong ứng dụng sử dụng REST API, Frontend hoặc Mobile App gửi Request đến Backend để lấy dữ liệu và thực hiện các thao tác. Đối với những API yêu cầu đăng nhập, Backend cần xác minh thông tin xác thực trước khi xử lý.

Ví dụ, một ứng dụng quản lý người dùng có thể có các API sau:

  • POST /auth/login: Kiểm tra thông tin đăng nhập và cấp Token nếu hợp lệ.
  • GET /users/me: Lấy thông tin của tài khoản đang đăng nhập.
  • PATCH /users/me: Cập nhật thông tin của tài khoản đang đăng nhập.
  • POST /auth/refresh: Yêu cầu cấp Access Token mới.
  • POST /auth/logout: Đăng xuất hoặc thu hồi Token theo cơ chế của hệ thống.

Khi người dùng gọi API lấy thông tin cá nhân, Client gửi Access Token trong Authorization Header. Backend xác minh Token để xác định người dùng đang thực hiện yêu cầu. Sau đó, hệ thống kiểm tra quyền truy cập và trả về dữ liệu phù hợp.

Nếu người dùng chưa cung cấp thông tin xác thực hợp lệ, API thường trả về HTTP 401 Unauthorized. Nếu người dùng đã được xác thực nhưng không có quyền thực hiện hành động, API thường trả về HTTP 403 Forbidden.

Điểm quan trọng là JWT không thay thế Authorization. Ví dụ, dù Token hợp lệ và xác định được người dùng có mã user_123, Backend vẫn phải kiểm tra người dùng đó có quyền truy cập hoặc chỉnh sửa dữ liệu đang được yêu cầu hay không.

7. Những vấn đề bảo mật cần lưu ý

7.1. Không lưu thông tin nhạy cảm trong Payload

Payload của JWT thông thường có thể được đọc nếu người khác lấy được Token. Vì vậy, không nên đưa mật khẩu, khóa bí mật hoặc những thông tin nhạy cảm vào Payload với suy nghĩ rằng chữ ký sẽ che giấu nội dung.

Chữ ký chỉ giúp kiểm tra tính toàn vẹn của Token, không mã hóa nội dung. Nếu cần bảo vệ tính bí mật của dữ liệu, cần sử dụng cơ chế mã hóa phù hợp và hạn chế đưa dữ liệu nhạy cảm vào Token.

7.2. Thiết lập thời hạn Token phù hợp

Token không nên có thời hạn quá dài nếu không có lý do phù hợp. Nếu Token bị đánh cắp, người khác có thể sử dụng nó trong phạm vi quyền hạn và thời gian Token còn hiệu lực.

Vì vậy, hệ thống cần thiết lập thời hạn cho Access Token, quản lý Refresh Token và có phương án xử lý khi người dùng đăng xuất hoặc tài khoản bị xâm phạm.

7.3. Bảo vệ nơi lưu trữ Token

Token cần được lưu trữ theo cách phù hợp với kiến trúc ứng dụng. Đối với Website, Cookie có các thuộc tính như HttpOnly, Secure và SameSite có thể giúp giảm một số rủi ro khi được cấu hình đúng.

Nếu lưu Token trong Local Storage, ứng dụng cần chú ý đến nguy cơ Token bị lấy cắp khi xảy ra lỗ hổng XSS. Ngược lại, nếu sử dụng Cookie để gửi thông tin xác thực tự động, hệ thống cũng cần xem xét nguy cơ CSRF.

Không có phương thức lưu trữ nào an toàn tuyệt đối trong mọi trường hợp. Lập trình viên cần lựa chọn dựa trên kiến trúc và các rủi ro của ứng dụng.

7.4. Xác minh JWT đầy đủ

Backend không nên chỉ giải mã JWT rồi tin tưởng vào nội dung bên trong. Hệ thống cần xác minh chữ ký, thời hạn và các Claim liên quan.

Ngoài ra, cần giới hạn thuật toán được phép sử dụng, kiểm tra Issuer và Audience khi phù hợp, đồng thời đảm bảo Token được sử dụng đúng mục đích.

7.5. Luôn kiểm tra quyền tại Backend

Token hợp lệ chỉ giúp hệ thống xác định yêu cầu đáp ứng các điều kiện xác thực. Điều này không có nghĩa người dùng được phép truy cập tất cả dữ liệu.

Backend vẫn phải kiểm tra quyền thực hiện hành động và quyền truy cập tài nguyên. Ví dụ, người dùng không thể chỉnh sửa hồ sơ của người khác chỉ bằng cách thay đổi mã người dùng trong URL hoặc Request.

7.6. Sử dụng HTTPS

HTTPS giúp mã hóa dữ liệu truyền giữa Client và Server, giảm nguy cơ Token bị đọc trộm trên đường truyền. Tuy nhiên, HTTPS không thể bảo vệ Token nếu Token đã bị lấy cắp từ thiết bị hoặc bị lộ thông qua lỗi trong ứng dụng.

Do đó, cần kết hợp HTTPS với việc lưu trữ Token an toàn, kiểm tra quyền truy cập và quản lý thời hạn sử dụng phù hợp.

8. Mối quan hệ với các khái niệm khác

  • Authentication: Xác minh danh tính người dùng hoặc hệ thống.
  • Authorization: Kiểm tra quyền truy cập tài nguyên và thực hiện hành động.
  • REST API: Cung cấp giao diện để Client giao tiếp với Backend.
  • HTTP Authorization Header: Nơi thường được sử dụng để gửi Bearer Token trong Request.
  • Session Management: Quản lý trạng thái đăng nhập và phiên sử dụng của người dùng.
  • OAuth 2.0: Khung ủy quyền cho phép Client nhận quyền truy cập tài nguyên theo cơ chế được quy định.
  • OpenID Connect: Lớp xác thực dựa trên OAuth 2.0, hỗ trợ xác minh danh tính người dùng.
  • Refresh Token: Token dùng để yêu cầu cấp Access Token mới.
  • HTTPS: Bảo vệ dữ liệu trong quá trình truyền tải.
  • XSS và CSRF: Các nhóm lỗ hổng bảo mật có thể ảnh hưởng đến việc bảo vệ thông tin xác thực tùy theo cách ứng dụng được triển khai.

9. Kết luận

JWT và Token Authentication là những kiến thức quan trọng khi xây dựng chức năng đăng nhập cho Website, Mobile App và REST API. Token Authentication cho phép Client gửi Token trong những Request tiếp theo, còn JWT cung cấp một định dạng Token có cấu trúc rõ ràng và hỗ trợ xác minh tính toàn vẹn bằng chữ ký.

Khi triển khai thực tế, lập trình viên cần hiểu rõ sự khác nhau giữa Access Token, Refresh Token và ID Token; biết cách xác minh JWT; thiết lập thời hạn sử dụng; bảo vệ nơi lưu trữ Token và kiểm tra quyền truy cập ở Backend.

Sử dụng JWT không tự động làm cho hệ thống an toàn. Mức độ bảo mật phụ thuộc vào cách thiết kế toàn bộ quy trình xác thực, phân quyền, quản lý phiên và xử lý dữ liệu. Vì vậy, cần lựa chọn phương thức phù hợp với yêu cầu của dự án thay vì sử dụng JWT chỉ vì đây là công nghệ phổ biến.

Các từ khóa cần ghi nhớ: JWT, Token Authentication, Access Token, Refresh Token, ID Token, Header, Payload, Signature, Claim, Bearer Token, Session-Based Authentication, REST API, OAuth 2.0, OpenID Connect, HTTPS, XSS, CSRF.

Bài viết khác

Authentication và Authorization

1. Authentication & Authorization là gì? Authentication và Authorization là hai khái niệm quan trọng trong bảo mật hệ thống, đặc biệt khi phát triển Website, Mobile App và REST API. Cả hai đều giúp kiểm soát việc truy cập vào hệ thống nhưng đảm nhiệm hai chức năng khác nhau. Authentication là quá trình xác […]

API Error Handling 

1. API Error Handling là gì? API Error Handling là quá trình xử lý các lỗi có thể xảy ra trong quá trình API tiếp nhận Request, thực hiện xử lý dữ liệu và trả về Response cho Client. Mục đích là giúp hệ thống nhận biết lỗi, xử lý lỗi một cách phù hợp […]

API Validation

1. API Validation là gì? API Validation là quá trình kiểm tra tính hợp lệ của dữ liệu khi Client gửi Request đến API. Mục đích là đảm bảo dữ liệu đáp ứng các điều kiện mà hệ thống yêu cầu trước khi được xử lý hoặc lưu vào Database. Ví dụ khi người dùng […]

Test Scenario(Kịch bản kiểm thử)

1. Lời mở đầu và vị trí chiến lược của Test Scenario trong quy trình kiểm thử: Trong bức tranh tổng thể của vòng đời kiểm thử phần mềm (STLC), sau khi đã hoàn thành việc phân tích yêu cầu và lập kế hoạch kiểm thử (Test Plan), công việc tiếp theo mang tính chất […]

Dart OOP

OOP là từ viết tắt của cụm từ Object Oriented Programming. Nó có nghĩa là lập trình hướng đối tượng. Đây là một phương pháp lập trình dựa trên những khái niệm về đối tượng và lớp. OOP thường tập trung vào những đối tượng thao tác hơn là tập trung vào logic để có […]

Dart Fundamentals

Dart là gì? Dart là một ngôn ngữ lập trình hướng đối tượng, mã nguồn mở, được phát triển bởi Google vào năm 2011. Ngôn ngữ này được tối ưu hóa đặc biệt cho việc phát triển giao diện người dùng (UI) mượt mà trên nhiều nền tảng (Mobile, Web, Desktop). Dart thường được gắn […]

Leave a Reply

Your email address will not be published. Required fields are marked *