Helpex - Trao đổi & giúp đỡ Đăng nhập

Cookie so với Tokens: Hướng dẫn cuối cùng

Chúng tôi sẽ viết một ứng dụng Angular 2 sử dụng JWT để xác thực. Lấy repo Github nếu bạn muốn theo dõi.

Bài viết cuối cùng của chúng tôi so sánh cookie với xác thực mã thông báo là hơn hai năm trước. Kể từ đó, chúng tôi đã viết nhiều về cách tích hợp xác thực mã thông báo trên nhiều ngôn ngữ và khuôn khổ khác nhau.

Sự gia tăng của các ứng dụng trang đơn (SPA) và sự tách biệt của front-end khỏi back-end đang có hiệu lực mạnh mẽ. Các khung công tác như Angular , ReactVue cho phép các nhà phát triển xây dựng các ứng dụng trang đơn lớn hơn, tốt hơn và hiệu suất hơn bao giờ hết. Xác thực dựa trên mã thông báo đi đôi với các khuôn khổ này.

 

"Xác thực dựa trên mã thông báo đi đôi với các khuôn khổ SPA như Angular, React và Vue."

 

Xác thực cookie so với mã thông báo - Tóm tắt

Trước khi đi sâu hơn, chúng ta hãy nhanh chóng tóm tắt lại cách hoạt động của hai hệ thống xác thực này. Nếu bạn đã quen với cách hoạt động của xác thực cookie và mã thông báo, vui lòng bỏ qua phần này, nếu không, hãy đọc tiếp để biết tổng quan chuyên sâu.

Sơ đồ này là một giới thiệu tuyệt vời và tổng quan đơn giản về sự khác biệt giữa các phương pháp tiếp cận cookie và mã thông báo để xác thực.

Cookie so với Tokens: Hướng dẫn cuối cùng

Xác thực dựa trên cookie

Xác thực dựa trên cookie đã là phương pháp mặc định, đã được thử và đúng để xử lý xác thực người dùng trong một thời gian dài.

Xác thực dựa trên cookie là trạng thái . Điều này có nghĩa là bản ghi hoặc phiên xác thực phải được lưu giữ cả máy chủ và phía máy khách. Máy chủ cần theo dõi các phiên hoạt động trong cơ sở dữ liệu, trong khi trên giao diện người dùng, một cookie được tạo để chứa mã nhận dạng phiên, do đó xác thực dựa trên cookie tên. Hãy xem quy trình xác thực dựa trên cookie truyền thống:

  1. Người dùng nhập thông tin đăng nhập của họ.
  2. Máy chủ xác minh thông tin đăng nhập là chính xác và tạo một phiên sau đó được lưu trữ trong cơ sở dữ liệu.
  3. Một cookie với ID phiên được đặt trong trình duyệt của người dùng.
  4. Trong các yêu cầu tiếp theo, ID phiên được xác minh dựa trên cơ sở dữ liệu và nếu hợp lệ, yêu cầu sẽ được xử lý.
  5. Sau khi người dùng đăng xuất khỏi ứng dụng, phiên sẽ bị hủy cả phía máy khách và phía máy chủ.

Xác thực dựa trên mã thông báo

Xác thực dựa trên mã thông báo đã trở nên phổ biến trong vài năm qua do sự gia tăng của các ứng dụng trang đơn, API web và Internet of Things (IoT). Khi chúng ta nói về xác thực bằng mã thông báo, chúng ta thường nói về xác thực với Mã thông báo web JSON (JWT). Mặc dù có nhiều cách khác nhau để triển khai mã thông báo, JWT đã trở thành tiêu chuẩn thực tế. Với bối cảnh này, phần còn lại của bài viết sẽ sử dụng mã thông báo và JWT thay thế cho nhau.

Xác thực dựa trên mã thông báo là không trạng thái . Máy chủ không lưu hồ sơ về người dùng nào đã đăng nhập hoặc JWT đã được cấp. Thay vào đó, mọi yêu cầu đến máy chủ đều đi kèm với một mã thông báo mà máy chủ sử dụng để xác minh tính xác thực của yêu cầu. Mã thông báo thường được gửi dưới dạng tiêu đề Ủy quyền bổ sung ở dạng Bearer {JWT}, nhưng cũng có thể được gửi trong phần nội dung của yêu cầu POST hoặc thậm chí dưới dạng tham số truy vấn. Hãy xem quy trình này hoạt động như thế nào:

  1. Người dùng nhập thông tin đăng nhập của họ.
  2. Máy chủ xác minh thông tin đăng nhập là chính xác và trả về mã thông báo đã ký.
  3. Mã thông báo này được lưu trữ phía máy khách, phổ biến nhất là trong bộ nhớ cục bộ - nhưng cũng có thể được lưu trữ trong bộ nhớ phiên hoặc cookie.
  4. Các yêu cầu tiếp theo đến máy chủ bao gồm mã thông báo này dưới dạng tiêu đề Ủy quyền bổ sung hoặc thông qua một trong các phương pháp khác được đề cập ở trên.
  5. Máy chủ giải mã JWT và nếu mã thông báo hợp lệ sẽ xử lý yêu cầu.
  6. Sau khi người dùng đăng xuất, mã thông báo sẽ bị hủy ở phía máy khách, không cần tương tác với máy chủ.

Ưu điểm của xác thực dựa trên mã thông báo

Hiểu được cách thức hoạt động của một thứ mới chỉ là một nửa của trận chiến. Tiếp theo, chúng tôi sẽ đề cập đến các lý do tại sao xác thực mã thông báo lại được ưu tiên hơn so với phương pháp dựa trên cookie truyền thống.

Không trạng thái, có thể mở rộng và tách rời

Có lẽ lợi thế lớn nhất của việc sử dụng mã thông báo trên cookie là thực tế rằng xác thực mã thông báo là không trạng thái. Back-end không cần lưu giữ hồ sơ về mã thông báo. Mỗi mã thông báo là độc lập, chứa tất cả dữ liệu cần thiết để kiểm tra tính hợp lệ của nó cũng như truyền tải thông tin người dùng thông qua các xác nhận quyền sở hữu.

Sau đó, công việc duy nhất của máy chủ trở thành ký mã thông báo khi yêu cầu đăng nhập thành công và xác minh rằng các mã thông báo đến là hợp lệ. Trên thực tế, máy chủ thậm chí không cần ký mã thông báo. Các dịch vụ của bên thứ ba như Auth0 có thể xử lý việc phát hành mã thông báo và sau đó máy chủ chỉ cần xác minh tính hợp lệ của mã thông báo.

Tên miền chéo và CORS

Cookie hoạt động tốt với các miền riêng và miền phụ, nhưng khi nói đến việc quản lý cookie trên các miền khác nhau, nó có thể trở nên khó hiểu. Ngược lại, cách tiếp cận dựa trên mã thông báo với CORS được kích hoạt làm cho việc hiển thị API cho các dịch vụ và miền khác nhau trở nên tầm thường. Vì JWT là bắt buộc và được kiểm tra với mỗi lần gọi đến back-end, miễn là có mã thông báo hợp lệ, các yêu cầu có thể được xử lý. Có một số lưu ý cho điều này và chúng tôi sẽ giải quyết những vấn đề đó trong phần Câu hỏi và Mối quan tâm Thường gặp bên dưới.

Lưu trữ dữ liệu trong JWT

Với cách tiếp cận dựa trên cookie, bạn chỉ cần lưu trữ id phiên trong cookie. Mặt khác, JWT cho phép bạn lưu trữ bất kỳ loại siêu dữ liệu nào, miễn là JSON hợp lệ. Các JWT đặc tả quy định cụ thể loại khác nhau của tuyên bố rằng có thể được bao gồm như dành riêng, công cộng và tư nhân. Bạn có thể tìm hiểu thêm về các chi tiết cụ thể và sự khác biệt giữa các loại xác nhận quyền sở hữu trên trang web jwt.io.

Trong thực tế, điều này có nghĩa là JWT có thể chứa bất kỳ loại dữ liệu nào. Tùy thuộc vào trường hợp sử dụng của mình, bạn có thể chọn đưa ra số lượng xác nhận tối thiểu như id người dùng và thời hạn của mã thông báo hoặc bạn có thể quyết định bao gồm các xác nhận quyền sở hữu bổ sung như địa chỉ email của người dùng, người đã cấp mã thông báo, phạm vi hoặc quyền cho người dùng và hơn thế nữa.

Hiệu suất

Khi sử dụng xác thực dựa trên cookie, back-end phải thực hiện tra cứu, cho dù đó là cơ sở dữ liệu SQL truyền thống hay cơ sở dữ liệu thay thế NoSQL và quá trình khứ hồi có thể mất nhiều thời gian hơn so với việc giải mã mã thông báo. Ngoài ra, vì bạn có thể lưu trữ dữ liệu bổ sung bên trong JWT, chẳng hạn như cấp độ quyền của người dùng, bạn có thể lưu cho mình các lệnh gọi tra cứu bổ sung để lấy và xử lý dữ liệu được yêu cầu.

Ví dụ: giả sử bạn có tài nguyên API /api/orderstruy xuất các đơn đặt hàng mới nhất được đặt qua ứng dụng của bạn, nhưng chỉ những người dùng có vai trò quản trị viên mới có quyền truy cập để xem dữ liệu này. Trong cách tiếp cận dựa trên cookie, khi yêu cầu được thực hiện, bạn sẽ có một lệnh gọi đến cơ sở dữ liệu để xác minh rằng phiên đó hợp lệ, một lệnh khác để lấy dữ liệu người dùng và xác minh rằng người dùng có vai trò quản trị viên và cuối cùng là một lệnh thứ ba gọi để lấy dữ liệu. Mặt khác, với cách tiếp cận JWT, bạn có thể lưu trữ vai trò người dùng trong JWT, vì vậy khi yêu cầu được thực hiện và JWT được xác minh, bạn có thể thực hiện một lệnh gọi đến cơ sở dữ liệu để truy xuất đơn đặt hàng.

Sẵn sàng di động

Các API hiện đại không chỉ tương tác với trình duyệt. Được viết đúng cách, một API duy nhất có thể phục vụ cả trình duyệt và các nền tảng di động gốc như iOS và Android. Cookie và nền tảng di động gốc không kết hợp tốt với nhau. Mặc dù có thể, nhưng có nhiều hạn chế và cân nhắc khi sử dụng cookie với nền tảng di động. Mặt khác, token dễ triển khai hơn nhiều trên cả iOS và Android. Mã thông báo cũng dễ triển khai hơn đối với các ứng dụng và dịch vụ Internet of Things không có khái niệm về kho lưu trữ cookie.

Câu hỏi và Mối quan tâm Thường gặp

Trong phần này, chúng ta sẽ xem xét một số câu hỏi và mối quan tâm phổ biến thường phát sinh khi chủ đề xác thực mã thông báo xuất hiện. Trọng tâm chính ở đây sẽ là bảo mật nhưng chúng tôi sẽ kiểm tra các trường hợp sử dụng liên quan đến kích thước mã thông báo, lưu trữ và mã hóa.

Kích thước JWT

Nhược điểm lớn nhất của xác thực mã thông báo là kích thước của JWT. Cookie phiên là tương đối nhỏ so với JWT thậm chí nhỏ nhất. Tùy thuộc vào trường hợp sử dụng của bạn, kích thước của mã thông báo có thể trở thành vấn đề nếu bạn thêm nhiều xác nhận quyền sở hữu vào nó. Hãy nhớ rằng, mỗi yêu cầu đến máy chủ phải bao gồm JWT cùng với nó.

Lưu trữ Token ở đâu?

Với xác thực dựa trên mã thông báo, bạn được lựa chọn nơi lưu trữ JWT. Thông thường, JWT được đặt trong bộ nhớ cục bộ của trình duyệt và điều này hoạt động tốt cho hầu hết các trường hợp sử dụng. Có một số vấn đề khi lưu trữ JWT trong bộ nhớ cục bộ cần lưu ý. Không giống như cookie, bộ nhớ cục bộ được đóng hộp cát cho một miền cụ thể và dữ liệu của nó không thể được truy cập bởi bất kỳ miền nào khác kể cả miền phụ.

Thay vào đó, bạn có thể lưu trữ mã thông báo trong cookie, nhưng kích thước tối đa của cookie chỉ là 4kb, do đó có thể có vấn đề nếu bạn có nhiều xác nhận quyền sở hữu được đính kèm với mã thông báo. Ngoài ra, bạn có thể lưu trữ mã thông báo trong bộ nhớ phiên tương tự như bộ nhớ cục bộ nhưng sẽ bị xóa ngay sau khi người dùng đóng trình duyệt.

Bảo vệ XSS và XSRF

Bảo vệ người dùng và máy chủ của bạn luôn là ưu tiên hàng đầu. Một trong những mối quan tâm phổ biến nhất của các nhà phát triển khi quyết định có sử dụng xác thực dựa trên mã thông báo hay không là các tác động bảo mật. Hai trong số các vectơ tấn công phổ biến nhất mà các trang web phải đối mặt là Cross Site Scripting (XSS) và Cross-Site Request Forgery (XSRF hoặc CSRF).

Các cuộc tấn công Cross Site Scripting ) xảy ra khi một thực thể bên ngoài có thể thực thi mã trong trang web hoặc ứng dụng của bạn. Vectơ tấn công phổ biến nhất ở đây là nếu trang web của bạn cho phép các đầu vào không được làm sạch đúng cách. Nếu kẻ tấn công có thể thực thi mã trên miền của bạn, mã thông báo JWT của bạn sẽ dễ bị tấn công. CTO của chúng tôi trước đây đã lập luận rằng các cuộc tấn công XSS dễ đối phó hơn nhiều so với các cuộc tấn công XSRF vì chúng thường được hiểu rõ hơn. Nhiều khung công tác, bao gồm Angular, tự động làm sạch đầu vào và ngăn chặn việc thực thi mã tùy ý. Nếu bạn không sử dụng khung làm sạch đầu vào / đầu ra ngay lập tức, bạn có thể xem các plugin như cajado Google phát triển để hỗ trợ. Vệ sinh đầu vào là một vấn đề đã được giải quyết trong nhiều khung và ngôn ngữ và tôi khuyên bạn nên sử dụng khung hoặc plugin so với việc xây dựng của riêng bạn.

Yêu cầu chéo trang web Các cuộc tấn công giả mạo không phải là một vấn đề nếu bạn đang sử dụng JWT với bộ nhớ cục bộ. Mặt khác, nếu trường hợp sử dụng của bạn yêu cầu bạn lưu trữ JWT trong cookie, bạn sẽ cần phải bảo vệ khỏi XSRF. XSRF không dễ hiểu như các cuộc tấn công XSS. Giải thích cách thức hoạt động của các cuộc tấn công XSRF có thể tốn nhiều thời gian, vì vậy thay vào đó, hãy xem phần nàyhướng dẫn thực sự tốt giải thích chuyên sâu về cách thức hoạt động của các cuộc tấn công XSRF. May mắn thay, ngăn chặn các cuộc tấn công XSRF là một vấn đề khá đơn giản. Để đơn giản hóa quá mức, bảo vệ chống lại cuộc tấn công XSRF, máy chủ của bạn, khi thiết lập phiên với máy khách sẽ tạo ra một mã thông báo duy nhất (lưu ý đây không phải là JWT). Sau đó, bất cứ lúc nào dữ liệu được gửi đến máy chủ của bạn, một trường nhập ẩn sẽ chứa mã thông báo này và máy chủ sẽ kiểm tra để đảm bảo các mã thông báo khớp nhau. Một lần nữa, vì khuyến nghị của chúng tôi là lưu trữ JWT trong bộ nhớ cục bộ, bạn có thể sẽ không phải lo lắng về các cuộc tấn công XSRF.

Một trong những cách tốt nhất để bảo vệ người dùng và máy chủ của bạn là có thời gian hết hạn ngắn cho các mã thông báo. Bằng cách đó, ngay cả khi một mã thông báo bị xâm phạm, nó sẽ nhanh chóng trở nên vô dụng. Ngoài ra, bạn có thể duy trì một danh sách đen các mã thông báo bị xâm phạm và không cho phép các mã thông báo đó truy cập vào hệ thống. Cuối cùng, cách tiếp cận hạt nhân sẽ là thay đổi thuật toán ký, điều này sẽ làm mất hiệu lực của tất cả các mã thông báo đang hoạt động và yêu cầu tất cả người dùng của bạn đăng nhập lại. Cách tiếp cận này không dễ dàng được khuyến nghị, nhưng có sẵn trong trường hợp vi phạm nghiêm trọng.

Mã thông báo được ký, không được mã hóa

Mã thông báo web JSON bao gồm ba phần: tiêu đề, tải trọng và chữ ký. Định dạng của JWT là header.payload.signature. Nếu chúng tôi ký JWT bằng thuật toán HMACSHA256, thì bí mật 'suỵt' và trọng lượng của:

{
  "sub": "1234567890",
  "name": "Ado Kukic",
  "admin": true
}

JWT được tạo sẽ là:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFkbyBLdWtpYyIsImFkbWluIjp0cnVlLCJpYXQiOjE0NjQyOTc4ODV9.Y47kJvnHzU9qeJIN48_bVna6O0EDFiMiQ9LpNVDFymM

Điều rất quan trọng cần lưu ý ở đây là mã thông báo này được ký bởi thuật toán HMACSHA256, tiêu đề và tải trọng được mã hóa Base64URL, nó không được mã hóa. Nếu tôi truy cập jwt.io , dán mã thông báo này và chọn thuật toán HMACSHA256, tôi có thể giải mã mã thông báo và đọc nội dung của nó. Do đó, không nên nói rằng dữ liệu nhạy cảm, chẳng hạn như mật khẩu, không bao giờ được lưu trữ trong payload.

Nếu bạn phải lưu trữ dữ liệu nhạy cảm trong payload hoặc trường hợp sử dụng của bạn yêu cầu JWT bị che khuất, bạn có thể sử dụng Mã hóa web JSON (JWE). JWE cho phép bạn mã hóa nội dung của JWT để không ai khác ngoài máy chủ có thể đọc được. JOSE cung cấp một khuôn khổ tuyệt vời và các tùy chọn khác nhau cho JWE và có các SDK cho nhiều khuôn khổ phổ biến bao gồm NodeJSJava .

Xác thực dựa trên mã thông báo đang hoạt động với Auth0

Tại Auth0, chúng tôi đã viết SDK, hướng dẫn và quickstarts để làm việc với JWTs cho nhiều ngôn ngữ và các khuôn khổ bao gồm NodeJS , Java , Python , GoLang , và nhiều hơn nữa . Bài viết "Cookie vs. Tokens" cuối cùng của chúng tôi đã sử dụng khung công tác AngularJS, vì vậy, việc sử dụng Angular 2 cho các mẫu mã của chúng tôi ngày hôm nay là rất phù hợp.

Bạn có thể tải xuống mã mẫu từ repo GitHub của chúng tôi . Việc tải xuống các mẫu mã được ưu tiên hơn vì Angular 2 yêu cầu rất nhiều thiết lập ban đầu để bắt đầu. Nếu bạn chưa có, hãy đăng ký tài khoản Auth0 miễn phí để bạn có thể tự mình triển khai và thử nghiệm với các tính năng và tùy chọn khác nhau. Bắt đầu nào.

Thiết lập Máy chủ Back-end

Đầu tiên chúng tôi sẽ thiết lập máy chủ của mình. Chúng tôi sẽ xây dựng máy chủ của mình với NodeJS. Máy chủ sẽ hiển thị hai API: /ping/secured/ping. Cái đầu tiên sẽ được công bố rộng rãi cho bất kỳ ai có thể truy cập nó, trong khi cái thứ hai yêu cầu bạn phải xác thực để gọi nó. Cách thực hiện như sau:

// Include the modules needed for our server.
var http = require('http');
var express = require('express');
var cors = require('cors');
var app = express();
var jwt = require('express-jwt');

// Set up our JWT authentication middleware
// Be sure to replace the YOUR_AUTH0_CLIENT_SECRET and
// YOUR_AUTHO_CLIENT_ID with your apps credentials which
// can be found in your management dashboard at 
// https://manage.auth0.com
var authenticate = jwt({
  secret: new Buffer('YOUR_AUTH0_CLIENT_SECRET', 'base64'),
  audience: 'YOUR_AUTH0_CLIENT_ID'
});

app.use(cors());

// Here we have a public route that anyone can access
app.get('/ping', function(req, res) {
  res.send(200, {text: "All good. You don't need to be authenticated to call this"});
});

// We include the authenticate middleware here that will check for
// a JWT and validate it. If there is a token and it is valid the
// rest of the code will execute.
app.get('/secured/ping', authenticate, function(req, res) {
  res.send(200, {text: "All good. You only get this message if you're authenticated"});
})

var port = process.env.PORT || 3001;

// We launch our server on port 3001.
http.createServer(app).listen(port, function (err) {
  console.log('listening in http://localhost:' + port);
});

Đây là một thiết lập Node / Express khá chuẩn. Điều duy nhất mà chúng tôi đã làm là triển khai express-jwtphần mềm trung gian sẽ xác thực JWT. Vì chúng tôi đang thực hiện tích hợp này với Auth0, chúng tôi sẽ để Auth0 xử lý quá trình tạo và ký mã thông báo. Nếu không muốn sử dụng Auth0, chúng tôi có thể tạo và ký mã thông báo của riêng mình bằng jsonwebtokenmô-đun. Hãy xem một ví dụ về cách thực hiện điều này.

// Import modules
...
var jwt = require('jsonwebtoken');

var token = jwt.sign({ sub : "1234567890", name : "Ado Kukic", admin: true }, 'shhhh');

app.get('/token', function(req, res){
    res.send(token);
});

Nếu chúng tôi viết mã này, khởi chạy máy chủ và điều hướng đến, localhost:3001/tokenchúng tôi sẽ thấy một mã thông báo đã ký có chứa ba yêu cầu mà chúng tôi đã đưa ra. Các jsonwebtokenmô-đun cũng có thể được sử dụng để xác minh và giải mã thẻ. Để tìm hiểu thêm về nó, hãy xem repo của nó . Vì chúng tôi sẽ không tạo mã thông báo trên máy chủ của mình nên chúng tôi có thể xóa mã này.

Triển khai Front-end

Tiếp theo, chúng tôi sẽ triển khai ứng dụng Angular 2 của mình. Nếu bạn đang theo dõi từ repo GitHub của chúng tôi , bạn sẽ thấy hai tùy chọn cho giao diện người dùng. Một sử dụng systemjs trong khi Webpack khác để tải và quản lý các mô-đun của chúng tôi. Vì cách ưa thích để viết ứng dụng Angular 2 là với TypeScript, chúng tôi sẽ xây dựng ứng dụng mẫu của mình với TypeScript. Đối với bản demo của chúng tôi, chúng tôi sẽ làm việc ngoài thư mục systemjs . Ngoài ra, chúng tôi sẽ sử dụng angular2-jwt thư viện cung cấp các phương thức trợ giúp để thực hiện yêu cầu với các tiêu đề chính xác và cũng kiểm tra xem có tồn tại mã thông báo hợp lệ hay không.

Những điều đầu tiên trước tiên. Chúng tôi cần một điểm vào ứng dụng của mình và đó là index.html.

<html>
  <head>
    <base href="/">
    <title>Angular 2 Playground</title>
      <meta charset="UTF-8">
     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">

     <!-- We'll include the Auth0 Lock widget to handle authentication -->
     <script src="//cdn.auth0.com/js/lock-9.0.min.js"></script>

    <script src="node_modules/es6-shim/es6-shim.min.js"></script>
    <script src="node_modules/zone.js/dist/zone.js"></script>
    <script src="node_modules/reflect-metadata/Reflect.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>

    <script src="systemjs.config.js"></script>
    <script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>
  </head>
  <body>
    <app>Loading...</app>
  </body>
</html>

Tiếp theo, chúng tôi sẽ xác định điểm vào của ứng dụng Angular 2 của chúng tôi. Điều này sẽ được thực hiện trong một tệp có tên main.ts.

import { bootstrap } from '@angular/platform-browser-dynamic';
import {provide} from '@angular/core';
import {LocationStrategy, HashLocationStrategy} from '@angular/common';
import {RouteConfig, ROUTER_PROVIDERS, ROUTER_DIRECTIVES} from '@angular/router-deprecated';
import {HTTP_PROVIDERS} from '@angular/http';
// Here we load the angular2-jwt library
import {AUTH_PROVIDERS} from 'angular2-jwt';

import { App } from './app.component';

bootstrap(App, [
  HTTP_PROVIDERS,
  ROUTER_PROVIDERS,
  AUTH_PROVIDERS,
  provide(LocationStrategy, { useClass: HashLocationStrategy })
])

Chúng tôi sẽ xây dựng phần auth.service.tstiếp theo. Dịch vụ này sẽ cung cấp các phương pháp để người dùng đăng nhập và đăng xuất khỏi ứng dụng của chúng tôi. Đảm bảo thay thế YOUR_CLIENT_IDYOUR_DOMAINbằng cài đặt ứng dụng của bạn từ trang tổng quan quản lý Auth0 .

import {Injectable, NgZone} from '@angular/core';
import {Router} from '@angular/router-deprecated';
import {AuthHttp, tokenNotExpired} from 'angular2-jwt';

// Avoid name not found warnings
declare var Auth0Lock: any;

@Injectable()
export class Auth {
  // Replace YOUR_CLIENT_ID and YOUR_DOMAIN with your credentials
  lock = new Auth0Lock('YOUR_CLIENT_ID', 'YOUR_DOMAIN');
  refreshSubscription: any;
  user: Object;
  zoneImpl: NgZone;

  constructor(private authHttp: AuthHttp, zone: NgZone, private router: Router) {
    this.zoneImpl = zone;
    this.user = JSON.parse(localStorage.getItem('profile'));
  }

  public authenticated() {
    // Check if there's an unexpired JWT
    return tokenNotExpired();
  }

  public login() {
    // Show the Auth0 Lock widget
    this.lock.show({}, (err, profile, token) => {
      if (err) {
        alert(err);
        return;
      }
      // If authentication is successful, save the items
      // in local storage
      localStorage.setItem('profile', JSON.stringify(profile));
      localStorage.setItem('id_token', token);
      this.zoneImpl.run(() => this.user = profile);
    });
  }

  public logout() {
    localStorage.removeItem('profile');
    localStorage.removeItem('id_token');
    this.zoneImpl.run(() => this.user = null);
    this.router.navigate(['Home']);
  }
}

Bây giờ chúng ta đã có nền tảng hoàn chỉnh. Chúng tôi có thể bắt đầu xây dựng ứng dụng của mình. Chúng tôi sẽ xây dựng thành phần gốc của chúng tôi trong một tệp có tên app.component.ts.

import {Component} from '@angular/core';
import {RouteConfig, ROUTER_PROVIDERS, ROUTER_DIRECTIVES} from '@angular/router-deprecated';
import {HTTP_PROVIDERS} from '@angular/http';
import {AUTH_PROVIDERS} from 'angular2-jwt';

import {Home} from './home.component';
import {Ping} from './ping.component';
import {Profile} from './profile.component';
import {Auth} from './auth.service';

@Component({
  selector: 'app',
  providers: [ Auth ],
  directives: [ ROUTER_DIRECTIVES ],
  templateUrl: 'src/app.template.html',
  styles: [`.btn-margin { margin-top: 5px}`]
})
@RouteConfig([
  { path: '/home',  name: 'Home',  component: Home, useAsDefault: true },
  { path: '/ping',  name: 'Ping',  component: Ping },
  { path: '/profile',  name: 'Profile',  component: Profile }
])
export class App {

  constructor(private auth: Auth) {}

}

Bạn có thể nhận thấy từ siêu dữ liệu chỉ thị của chúng tôi rằng chúng tôi sẽ tải một mẫu bên ngoài có tên app.template.html. Mẫu Angular 2 có thể được nội dòng hoặc tham chiếu đến một tệp bên ngoài và vì mẫu của chúng tôi nằm ở phía dài hơn, chúng tôi sẽ đặt nó trong một tệp bên ngoài.

<nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <a class="navbar-brand" href="#">Auth0 - Angular 2</a>
      <button class="btn btn-primary btn-margin" [routerLink]=" ['Home'] ">Home</button>
      <button class="btn btn-primary btn-margin" [routerLink]=" ['Ping'] ">Ping</button>
      <button class="btn btn-primary btn-margin" [routerLink]=" ['Profile'] " *ngIf="auth.authenticated()">Profile</button>
      <button class="btn btn-primary btn-margin" (click)="auth.login()" *ngIf="!auth.authenticated()">Log In</button>
      <button class="btn btn-primary btn-margin" (click)="auth.logout()" *ngIf="auth.authenticated()">Log Out</button>
    </div>
  </div>
</nav>

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

Từ app.template.htmltệp của chúng tôi , chúng tôi thấy rằng chúng tôi sẽ có ba tuyến đường: Trang chủ , PingHồ sơ . Ngoài ra, có hai nút khác, Đăng nhập và Đăng xuất. Lệnh *ngIfhiển thị có điều kiện một số tuyến dựa trên việc người dùng có được xác thực hay không. Hãy xây dựng ba tuyến đường.

Thành phần Trang chủ

Thành phần nhà là tuyến đường mặc định được tải. Nó có thể truy cập công khai.

import {Component} from '@angular/core';

@Component({
  selector: 'home',
  template: `
    <h1>Welcome to auth0-angular2</h1>
    <p>
      This repo shows you how to set up authentication in your Angular 2 apps with Auth0.
      Get started by providing your Auth0 client ID and domain in the Auth0Lock widget in <code>auth/auth.service.ts</code>.
    </p>
  `
})
export class Home {
  constructor() {}
}

Thành phần ping

Thành phần ping tương tác với máy chủ NodeJS của chúng tôi mà chúng tôi đã xây dựng trước đó. Máy chủ Node sẽ cần phải chạy để bạn truy cập các tuyến này.

import {Component} from '@angular/core';
import {Http} from '@angular/http';

import {AuthHttp} from 'angular2-jwt';
import {Auth} from './auth.service';
import 'rxjs/add/operator/map';

@Component({
  selector: 'ping',
  template: `
    <h1>Send a Ping to the Server</h1>
    <p *ngIf="!auth.authenticated()">Log In to Get Access to a Secured Ping</p>
    <button class="btn btn-primary" (click)="ping()">Ping</button>
    <button class="btn btn-primary" (click)="securedPing()" *ngIf="auth.authenticated()">Secured Ping</button>
    <h2></h2>
  `
})
export class Ping {
  API_URL: string = 'http://localhost:3001';
  message: string;

  constructor(private http: Http, private authHttp: AuthHttp, private auth: Auth) {}

  ping() {
    this.http.get(`${this.API_URL}/ping`)
      .map(res => res.json())
      .subscribe(
        data => this.message = data.text,
        error => this.message = error._body
      );
  }

  securedPing() {
    this.authHttp.get(`${this.API_URL}/secured/ping`)
      .map(res => res.json())
      .subscribe(
        data => this.message= data.text,
        error => this.message = error._body
      );
  }
}

Thành phần hồ sơ

Thành phần hồ sơ hiển thị dữ liệu người dùng cho người dùng hiện đang đăng nhập. Thành phần này chỉ có thể được truy cập bởi một người dùng đã đăng nhập.

import {Component} from '@angular/core';
import {CanActivate} from '@angular/router-deprecated';
import {tokenNotExpired} from 'angular2-jwt';
import {Auth} from './auth.service';

@Component({
  selector: 'profile',
  template: `
    <h1>Profile</h1>
    <img [src]="auth.user.picture">
    <h2></h2>
    <span></span>
  `
})

@CanActivate(() => tokenNotExpired())

export class Profile {
  constructor(private auth: Auth) {}
}

Với ba thành phần được xây dựng, chúng tôi đã sẵn sàng khởi chạy ứng dụng của mình. Nếu bạn đang sử dụng repo GitHub được cung cấp, bạn có thể chỉ cần chạy gulp playvà mã của bạn sẽ được chuyển sang JavaScript và ứng dụng sẽ khởi chạy tại localhost:9000. Nếu bạn không sử dụng repo GitHub, bạn sẽ cần chuyển phiên bản sắp xếp hoặc thay đổi cấu hình systemjs để tải các tệp bản định dạng thay thế.

Điều hướng đến localhost:9000sẽ tải giao diện người dùng của chúng tôi cho ứng dụng sẽ giống như sau:

Cookie so với Tokens: Hướng dẫn cuối cùng

Bạn có thể điều hướng đến tab Ping và nhấp vào nút "Ping" để thực hiện cuộc gọi đến API Node của bạn và nó sẽ hiển thị thông báo chính xác. Nếu bạn nhấp vào nút Đăng nhập, bạn sẽ được nhắc đăng nhập bằng tiện ích Khóa Auth0 . Sau khi xác thực thành công, bạn sẽ có thể xem Hồ sơ của mình, đăng xuất và có khả năng gọi Ping bảo mật từ tab Ping.

Ứng dụng web tiến bộ

Chủ đề cuối cùng tôi muốn đề cập trước khi chúng ta kết thúc bài viết này là Ứng dụng web tiến bộ . Ứng dụng web tiến bộ cho phép ứng dụng dựa trên web của bạn hoạt động giống ứng dụng iOS hoặc Android dành cho thiết bị di động gốc hơn. Ứng dụng Web tiến bộ mang lại nhiều lợi thế bao gồm tăng hiệu suất, "có thể cài đặt" trên thiết bị di động và có thể hoạt động ngoại tuyến.

Angular 2, thông qua Bộ công cụ dành cho thiết bị di động , giúp bạn dễ dàng chuyển đổi ứng dụng Angular 2 thành Ứng dụng web tiến bộ. Có nhiều thành phần có thể làm cho ứng dụng của bạn tiến bộ hơn, cái mà chúng ta sẽ xem xét hôm nay là tệp kê khai ứng dụng web . Tệp kê khai này chỉ đơn giản là một tệp, tương tự như package.jsonví dụ, nơi bạn xác định các chi tiết cụ thể cho ứng dụng của mình. Khi trang web của bạn được truy cập trên thiết bị di động, tệp kê khai này có thể được đọc và dựa trên thông tin bên trong các hành động nhất định được thực hiện như đặt tên ứng dụng hoặc đặt hướng của ứng dụng. Hãy xem một tệp kê khai ứng dụng, có tiêu đề manifest.webappvà xem chúng tôi có thể đặt những tùy chọn nào:

 {
   "name": "Auth0 Angular 2 App",
   "short_name": "A0 Angular 2 App",
   "icons": [
     {
             "src": "/android-chrome-36x36.png",
             "sizes": "36x36",
             "type": "image/png",
             "density": 0.75
         },
         {
             "src": "/android-chrome-48x48.png",
             "sizes": "48x48",
             "type": "image/png",
             "density": 1
         },
         {
             "src": "/android-chrome-72x72.png",
             "sizes": "72x72",
             "type": "image/png",
             "density": 1.5
         },
         {
             "src": "/android-chrome-96x96.png",
             "sizes": "96x96",
             "type": "image/png",
             "density": 2
         },
         {
             "src": "/android-chrome-144x144.png",
             "sizes": "144x144",
             "type": "image/png",
             "density": 3
         },
         {
             "src": "/android-chrome-192x192.png",
             "sizes": "192x192",
             "type": "image/png",
             "density": 4
         }
   ],
   "theme_color": "#000000",
   "background_color": "#e0e0e0",
   "start_url": "/index.html",
   "display": "standalone",
   "orientation": "portrait"
 }

Phần kết luận

Trong bài viết hôm nay, chúng tôi đã so sánh sự khác biệt giữa xác thực dựa trên cookie và mã thông báo. Chúng tôi đã nêu bật những ưu điểm và mối quan tâm của việc sử dụng mã thông báo và cũng đã viết một ứng dụng đơn giản để giới thiệu cách JWT hoạt động trong thực tế. Có nhiều lý do để sử dụng mã thông báo và Auth0 ở đây để đảm bảo rằng việc triển khai xác thực mã thông báo dễ dàng và an toàn. Cuối cùng, chúng tôi đã giới thiệu Ứng dụng web tiến bộ để giúp làm cho các ứng dụng web của bạn trở nên nguyên bản hơn trên thiết bị di động. Đăng ký một tài khoản miễn phí ngay hôm nay và thiết lập và chạy trong vài phút.

8 hữu ích 0 bình luận 220k xem chia sẻ

Có thể bạn quan tâm

loading