- vừa được xem lúc

Làm chức năng đăng nhập bằng QR Code giống Zalo

0 0 25

Người đăng: Bùi Việt Hoàng

Theo Viblo Asia

Mở đầu

  • Một chức năng khá tiện cho các trường hợp quên mật khẩu nhưng vẫn còn session trên điện thoại.
  • Với đức tính thích tìm tòi, nghịp ngợm chàng sinh viên tên Hoàng đã mở F12 và sau đó ....... Có bài viết này 😂

1. Luồng hoạt động

  1. Đầu tiên khi vào trang chủ zalo phiên bản web id.zalo.me một request đến
POST https://id.zalo.me/account/authen?a=qr&t=1

và response trả về có dạng

{ "code": "A", // Dùng để nhận dạng trình duyệt đang đăng nhập "image: "B", // Ảnh qrcode dưới dạng base64 "token": "C" // Nội dung trong QRCode
}

Vấn đề đầu tiên: Làm sao nhận dạng được trình duyệt để khi điện thoại quét QR Code thành công mình còn thực hiện các thao tác như xác nhận thông tin, cấp token và chuyển hướng nó đến trang chủ.

  1. Tiếp theo thực hiện request thứ 2 đến https://id.zalo.me/account/authen?a=qr&t=2 với code gửi kèm trong body.

Điểm khá thú vị request này sẽ mãi ở trạng thái pending. Nó chỉ success khi có người quét mã QR Code bằng ứng dụng zalo hoặc request timeout.

Đến đây mọi chuyện đã sáng tỏ, zalo dựa vào "code" để cấp mã nhận diện cho trình duyệt.

  1. Khi người dùng quét QR Code trong ứng dụng, app sẽ gửi request lên zalo để xác nhận. Nếu thành công thì request ở bước 2 nào có code tương ứng với token sẽ trả về dữ liệu là tên người dùng.

  1. Đến bước này có thể cho người dùng đăng nhập. Nhưng zalo vẫn bắt thêm 1 bước xác nhận trên điện thoại nữa. Trình duyệt sẽ hiển thị avatar và tên người dùng lên màn hình, và request tiếp đến https://id.zalo.me/account/authen?a=qr&t=3 kèm với code

Vẫn giống như bước 2 request này vẫn sẽ pending cho đến khi người dùng xác nhận, từ chối trên điện thoại hoặc timeout.

  1. Nếu quá lâu không được quét, request ở bước 2, 3 sẽ timeout và yêu cầu người dùng tạo lại mã mới.

2. Thử triển khai demo nho nhỏ

Em sẽ dùng Expressjs để demo nhỏ nhé

  1. Đầu tiên viết API sinh code, qrcode, token
app.post("/account/authen", (req,res) => { const { t } = req.query; if(t == "1"){ // Sinh code và token random rồi lưu vào database // Tạo QRCode với token vừa tạo dạng base64 return res.send({ code, qrcode, token }) }
})
  1. Viết giao diện và call API /account/authen?t=1 để render ảnh QR và lưu lại code (các bác tự viết nhé).

  2. Tiếp tục viết API thứ 2 phía backend:

app.post("/account/authen", (req,res) => { const { t } = req.query; if(t == "1"){ // Sinh code và token random rồi lưu vào database // Tao QRCode với token vừa tạo dạng base64 return res.send({ code, qrcode, token }) } if(t == "2"){ // api này sẽ mãi pending cho đến khi nhận được event confirm của socket (như ảnh dưới) socket.on(`confirm-info-${req.body.code}`, ({ avatar, name}) => { return res.send({ avatar, name }); }); }
})

Sau đó request đến /account/authen?t=2 kèm theo code.

Việc giao tiếp giữa các controller có nhiều cách, ở đây em dùng socket cho nhanh.

  1. Thay vì viết 1 con app để đọc QR rồi gửi request để confim thì ta viết 1 api cho mobile rồi giả lập đt quét bằng postman.
app.post("/mobile/authen", (req, res) => { const { t } = req.query if(t == 2){ const { token, jwt } = req.body // Check jwt xem có hợp lệ không ? // Nếu có ? query database tìm code tương ứng với token // Hợp lệ emit socket io.emit(`comfirm-info-${code}`, { name: "Bùi Việt Hoàng" }) res.send("OK") }
})

  1. Request /account/authen?t=2 nhận được event của socket lập tức trả về tên của người dùng. Và tiếp tục request đến /account/authen?t=3 để chờ người dùng xác nhận

Cập nhật code backend

app.post("/account/authen", (req,res) => { const { t } = req.query; if(t == "1"){ // Sinh code và token random rồi lưu vào database // Tao QRCode với token vừa tạo dạng base64 return res.send({ code, qrcode, token }) } if(t == "2"){ // api này sẽ mãi pending cho đến khi nhận được event confirm của socket (như ảnh dưới) socket.on(`comfirm-info-${req.body.code}`, ({ avatar, name}) => { return res.send({ avatar, name }); }); } if(t == "3"){ // api này sẽ mãi pending cho đến khi nhận được event confirm của socket socket.on(`comfirm-auth-${req.body.code}`, () => { // sinh token jwt và trả về cho trình duyệt web có thể đăng nhập return res.send({ jwt }); }); }
})
app.post("/mobile/authen", (req, res) => { const { t } = req.query if(t == 2){ const { token, jwt } = req.body // Check jwt xem có hợp lệ không ? // Nếu có ? Query database tìm code tương ứng với token // Hợp lệ emit socket với code vừa query io.emit(`comfirm-info-${code}`, { name: "Bùi Việt Hoàng" }) res.send("OK") } if(t == "3"){ // Kiểm tra xác thực trên đt io.emit(`comfirm-auth-${code}`, {}) res.send("OK") }
})
  1. Nếu request /account/authen?t=3thành công chuyển hướng người dùng đến trang chủ
  2. Xử lý timeout ta viết 1 middleware để xử lý.
app.use(function(req, res, next){ res.setTimeout(2000000, function(){ console.log('Mã qr hết hạn, vui lòng tạo mới.'); res.status(408).send(); }); next();
});

Kết

Nếu có gì sai sót mong nhận được góp ý từ các bác 😘😘

Bình luận

Bài viết tương tự

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

0 0 393

- vừa được xem lúc

Hướng dẫn làm bot Facebook messenger cho tài khoản cá nhân

Giới thiệu. Trong bài viết trước thì mình có hướng dẫn các bạn làm chatbot facebook messenger cho fanpage. Hôm nay mình sẽ hướng dẫn các bạn tạo chatbot cho một tài khoản facebook cá nhân. Chuẩn bị.

0 0 174

- vừa được xem lúc

Crawl website sử dụng Node.js và Puppeteer - phần 2

trong phần 1 mình đã giới thiệu về puppeteer và tạo được 1 project cùng một số file đầu tiên để các bạn có thể crawl dữ liệu từ một trang web bất kỳ. Bài này mình sẽ tiếp nối bài viết trước để hoàn thiện seri này.

0 0 72

- vừa được xem lúc

Điều React luôn giữ kín trong tim

■ Mở đầu. Ngồi viết bài khi đang nghĩ vu vơ chuyện con gà hay quả trứng có trước, mình phân vân chưa biết sẽ chọn chủ đề gì để chúng ta có thể cùng nhau bàn luận.

0 0 57

- vừa được xem lúc

Gửi Mail với Nodejs và AWS SES

AWS SES. AWS SES là gì.

0 0 81

- vừa được xem lúc

Crawl website sử dụng Node.js và Puppeteer - phần 1

Bài viết này mình sẽ giới thiệu cho các bạn craw dữ liệu của web site sử dụng nodejs và Puppeteer. .

0 0 163