Xác thực người dùng bằng JWT

Cho mình hỏi vấn đề này với ạ.
Mình viết một ứng dụng có chức năng người dùng đăng nhập như nhiều sách, bài viết đã giải thích như sau. người dùng sẽ nhập username và password để gửi lên server, server xác thực username và password đó. Nếu ok thì sẽ trả về token, refresh token (dự kiến như vậy), và expire time. sau đó người dùng dùng token đó để access resource trên server. Về phía client mình có những thắc mắc sau.

  1. Dùng điều kiện gì để kiểm tra người dùng đã đăng nhập chưa để hiện thị màn hình đăng nhập khi khởi động app. Có phải chỉ cần kiểm tra trong localstorage (đại loại là vậy) có giá trị access token hay không là đủ? Nếu có thì vào thẳng màn hình chính, nếu chưa thì vào màn hình đăng nhập.
  2. Nếu ở trên dùng access token để kiểm tra đã đăng nhập hay chưa thì làm thế nào để kiểm tra access token đó có hợp lệ hay không. Hợp lệ ở đây nghĩa là token chưa expire. Hay là phải gửi request nào đó để kiểm tra có hợp lệ hay không?
  3. Vì access token có thời gian expire ngắn nên để ứng dụng sử dụng một cách liên tục không bị gián đoạn và người dùng không phải đăng nhập lại nhiều lần thì làm thế nào để thực hiện như vậy? Mình đang nghĩ tới việc dùng refresh token để lấy lại token mới khi hết hạn. Và lại có nhiều thắc mắc nữa.
    3a. Khi nào thì cần lấy lại token mới? trước khi token cũ expire hay sau khi expire?
    3b. Làm thế nào để kiểm tra token đó expire hay chưa? Dùng expire time trả về để kiểm tra token đó khi nào hết hạn. Dùng timer hoặc cách gì đó để trước khi expire thì sẽ lấy token mới bằng refresh token rồi cập nhật vào localstorage.
    3c. Có phải chỉ cần token chưa expire thì nó luôn luôn có thể truy cập vào server resource không? Nếu user đổi mật khẩu hay thay đổi gì đó ở thiết bị khác thì token này có còn hợp lệ không. Cái này mình chưa hiểu rõ lắm về token.
    3d. Làm thế nào để tránh trường hợp người dùng đang mở ứng dụng mà token bị hết hạn dẫn để bị lỗi.

Những ứng dụng như Facebook, Zalo… chắc cũng dùng access token để xác thực? Vậy làm thế nào họ có thể duy trì ứng dụng đăng nhập một cách lâu như vậy?

Xin lỗi mình dùng tiếng Anh tiếng Việt lẫn lỗn. Cảm ơn ạ.

Server có hàm Get_List_Products(), trước nó làm 1 cái filter, client request lên gặp cái filter này đầu tiên, nếu đúng thì cho vào Get_List_Products(), sai token thì trả về 401.

Client gửi request lên Get_List_Products() thì trong header của request có đính kèm bearer Token.

Dùng UNIX Time

Không. expire phải hợp lệ, header, payload, chữ kí mã hóa không bị chỉnh sửa, còn nguyên vẹn.

Không.

1 Like
  • Mình nghĩ bạn cần xem lại kiến thức về JWT, cách check expire có trong đặc tả của JWT rất rõ ràng
  • Đây là vấn đề của thiết kế, không phải kĩ thuật, bạn muốn có thì là có, bạn muốn không thì là không
  • Tư tự câu trên, đây cũng là vấn đề của thiết kế

Lỗi mà có thể đoán trước được thì không phải là lỗi, và câu này cũng là vấn đề thiết kế, token expire thì app sẽ như nào, trở về màn hình log in hay refresh token thì do thiết kế hay do ý bạn code thôi

3 Likes

Những lần truy cập vào resource thì tất nhiên phải kèm token vào trong header, điều này thì mình biết rồi.
Còn ví dụ ở lần mở ứng dụng tiếp theo, user chưa gửi request gì lên server cả mà chỉ mới dùng những tính năng như offline. Vậy thì khi mở ứng dụng lên làm thế nào để kiểm tra xem token đấy còn hợp lệ hay không? Bằng cách kiểm tra time expiration hay gửi test request để kiểm tra? hay phải đợi tới lúc cần request rồi mới biết token đấy hợp lệ hay không. Nếu đợi tới lúc cần mới gửi thì trong lúc user đang dùng ứng dụng sẽ có nguy cơ bị lỗi do token expire. Để tránh như vậy thì trong code khi gửi tất cả request đều phải kiểm tra,nếu bị lỗi do token expire thì renew token mới.

ý bạn là dùng expire time của token khi nhận từ sever về rồi so sánh thời gian đó với thời gian hiện tại đúng không ạ?

Cảm ơn bạn lại giúp đỡ mình.

Hầu hết đều là do thiết kế nhỉ :grinning: Nhưng vấn đề của mình là mình chưa có kinh nghiệm thiết kế nên mình muốn biết xem người ta thiết kế thế nào để không bị sai hướng tiêu chuẩn.

2 Likes

trong phần payload của token đã gửi về client có thời gian hết hạn là số UNIX Time, nếu offline client parse token, lấy ra payload, trong paload lấy ra UNIX Time rồi so sánh độ lệch với UNIX Time hiện tại để biết hết hiệu lực chưa.

1 Like

thiết kế là dựa trên ý muốn của người dùng, ý muốn của khách hàng, mà đó lại không phải là chuyện của dev
nếu bạn muốn biết thị hiếu người dùng thích như nào thì thực tế có khi người dùng không biết họ muốn cái gì nữa, tới khi bạn có cái (sản phẩm, demo) cho họ xài (tham khảo) họ mới nhận ra là họ cần cái này chứ không cần cái kia
Còn thị hiếu chung chung thì bạn cứ xem các product lớn nó có tính năng gì thì cứ làm theo, ví dụ như facebook có thể quản lý danh sách các thiết bị login bla bla

2 Likes

Cách này mình cũng có thấy có một vài người làm rồi. tương tự như hàm isTokenExpired của bạn này Mobile-FE-Chat/index.js at master · thanhtung5598/Mobile-FE-Chat (github.com)
Nhưng mà như thế này thì chỉ kiểm tra theo thời gian một cách offline ở phía client thôi chứ không phải kiểm tra với sever.

Như bạn nói ở trên nếu người dùng đổi password ở máy khác, token bị vô hiệu trong khi ở máy này token vẫn còn thời gian, chưa expire thì đối với máy này khi mở ứng dụng lên token vẫn hưu hiệu (do chưa expire) nghĩa là vẫn login bình thường rồi đến khi đang dùng ứng dụng cần request lúc đó mới biết lỗi.

Cái dự án này là do mình làm sản phẩm cho cá nhân không phải khách hàng. Làm cho cá nhân thì được cái tự do là thích làm gì thì làm. Nhưng cũng có cái khó hơn là vì làm cho cá nhân nên yêu cầu không rõ ràng nên dễ thay đổi quan điểm cách làm trong quá trình làm. Mặc dù làm cá nhân thì sao cũng được nhưng mình hơi tham lam là muốn làm theo các ông lớn như Facebook này nọ. Vừa muốn dự án của mình cũng lớn, vừa muốn biết được cách người ta làm như thế nào.

Mình nghĩ là không thể xử lí UX mượt ở tình huống này được, chỉ có cách bật app lên, bật wifi và thao tác đợi server báo 200 hay là 401, chứ server không chủ động tự gửi dữ liệu xuống client được, cái này socket mới làm được. Tình huống đổi pass, logout, đăng nhập nhiều thiết bị theo mình thì server phải cần đến database để lưu tạm token, gửi xuống cái nào thì lưu lại cái đó luôn, device nào logout thì xóa đồng thời token tương ứng ở client, và trên server(nếu chỉ xóa ở client thì sợ trường hợp token ở client bị hacker chôm trước đó và nó vẫn còn hiệu lực), còn nếu logout all device thì server xóa hết token (nhưng client vẫn còn) thì phải đợi connect với server và đợi nó gửi về 200 hay 401 để xử lý UX tiếp. Đây là ý tưởng của mình, bạn thấy hợp lý không?

1 Like

Trường hợp mình token chưa expire và có wifi thì sao ạ? Do mình làm cả server và client nên mình có thể chỉnh sửa ở server được. Hay là mình làm thêm phần để xác thực bằng token để khi ứng dụng client mở lên sẽ gửi request tới endpoint đó. sẽ trả về một response trống và http status code?

Cái này thì mình thấy hợp lý và sẽ lưu lại để làm sau.

cmt trước mình có nói đến dùng filter á.

resource nào mà public như danh sách sản phẩm đang bán, tin tức, … thì không cần token, resource nào cần bảo vệ thì bạn làm một cái filter (ASP.net core cấu hình trong ConfigureServices(IServiceCollection services) file Startup.cs á, và dùng dataannotations cho controller cần được bảo vệ).
Server bạn có thể tạo hàm checkValidToken trả về mã lỗi hay bool gì đó. App client theo user case như này: mở app lên => app hỏi server token còn dùng nữa được không?

  • TH1 : => token không dùng được-> chạy ngầm thao tác xóa token, user vẫn lướt xem sản phẩm, đọc báo như chưa có gì xảy ra… đến khi thêm vào giỏ hàng, thanh toán thì chuyển thẳng qua trang login luôn kèm theo “vui lòng login để tiếp tục.”. Làm theo thì cho mua, cancel thì redirect về home.
  • TH2 : => token vẫn dùng bình thường thì mọi chức năng đều được mở khóa.

User mới bật app mà đầu tiên hiện ngay popup bắt đăng nhập lại rất khó chịu.

Bạn thấy UX như vậy có mượt chưa.

2 Likes

Trường hợp mình nếu không login được thì sẽ không vào được ứng dụng luôn vì ứng dụng của mình không phải là bán hàng mà là home control. Nhưng mình sẽ dùng gợi ý của bạn là trên server tạo hàm để checkValidToken. Nếu mở lên check token bị lỗi sẽ bắt đăng nhập luôn. Còn UX của bạn mình nghĩ như vậy rất phù hợp. Cảm ơn bạn nhiều vì đã giúp đỡ nhiệt tình.

Mình viết flowchart như này bạn cho mình xin thêm ý kiến với.

Bạn xem video ví dụ JWT authen này, ASP có identity framework hỗ trợ đủ các hàm xác thực, bảo mật, phân quyền.

Như vậy ví dụ bạn muốn bảo về hàm

public string getResource(){
return 'Hello world';
}

Chỉ cần thêm dataAnnotations vào method (bạn tự config JWT authorization như trong video)

[Authorize]    
public string getResource(){
        return 'Hello world';
        }

Nó bao gồm cả trường hợp, token null, token lạ, token hết hạn, token bị fake, … thì bạn config trả về 401. client nhận được thông báo rồi xử lý tiếp

flowchart của client như này

if(ServerValidateToken){
// pass => cho truy cập resource
} else {
      redirect(LOGIN)
}

trên server mình đã dùng phương thức Authorize để bảo vệ resource rồi nhưng cũng chỉ mới config đơn giản thôi. Và sẽ config thêm những trường hợp bạn đã giới thiệu. Ở flowchart trên là mình hỏi về logic của client cụ thể là app mobile.

Bên trên là mình nói flowchart cho client đó bạn, mới bật app lên sẽ như này

if(ServerValidateTokenResponse(clientTOKEN)){
       redirect(HOME SCREEN)
} else {
      redirect(LOGIN SCREEN)
}
1 Like

Ok mình hiểu rồi. cảm ơn bạn nhiều ạ.

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?