+2

Tạo 1 custom Token mỗi khi đăng nhập và lưu vào database với Spring Boot - Thymeleaf - Elasticsearch kết hợp với sử dụng Kaizen Elastic. Tạo 1 function tại FE trigger gọi đến BE xin cấp token mới sau 1 khoảng thời gian chỉ định

Trong bài viết này, tôi sẽ hướng dẫn các phần chính sau:

  • Tải và sử dụng Kaizen
  • Phân loại user theo role. User với role admin sau khi login sẽ truy cập Admin dashboard page, user thường thì sẽ truy cập đến page khác
  • Tạo 1 token đơn giản sau mỗi lần đăng nhập và lưu token này vào trong database, không sử dụng JWT Token
  • Tạo 1 function kiểm token đã hết hạn hoặc chưa. Nếu token đã hết hạn -> call api bất kỳ -> báo lỗi 401
  • Tạo các function xử lý Thêm - Xoá - Sửa thông tin user tại Admin dashboard

Nội dung nâng cao:

  • Tạo 1 function tự động tại FE sau một thời gian nhất định -> được call để kiểm tra token hết hạn hoặc chưa và sẽ tự động xin cấp mới token và remove token cũ

Vui lòng tham khảo lại những bài viết sau để biết cách tạo 1 project với Spring Boot - Thymeleaf - Elasticsearch:

https://viblo.asia/p/tao-mot-project-voi-spring-boot-va-elasticsearch-841-su-dung-thu-vien-spring-data-elasticsearch-huong-dan-cai-dat-va-su-khac-nhau-giua-2-phien-ban-8xx-voi-7xx-elasticsearch-Rk74aRXvJeO

https://viblo.asia/p/tao-mot-project-voi-spring-boot-thymeleaf-elasticsearch-su-dung-http2-tao-service-run-elasticsearch-yZjJYjolLOE

https://viblo.asia/p/ma-hoa-thong-tin-password-trong-qua-trinh-login-register-voi-base64-su-dung-spring-boot-thymeleaf-elasticsearch-khong-su-dung-form-bXP4WPoBJ7G

Nguồn templates html: https://templatemo.com/tag/bootstrap-5

Công cụ và thư viện được sử dụng trong bài viết:

  • Spring boot 2.7.4
  • Spring tool suite 4
  • Spring data elasticsearch 4.4.2
  • Maven 3
  • Java 11
  • Elasticsearch 7.17.6
  • Elasticsearch head extension
  • Kaizen Elastic

1. Tải và sử dụng Kaizen:

Trong những bài viết trước đó tôi sử dụng extension "Elasticsearch head", vì nó nhẹ và cài đặt nhanh chóng, giao diện Elasticsearch Head:

image.png

Hôm nay tôi giới thiệu thêm 1 công cụ tương tự như Elasticsearch Head như hỗ trợ nhiều tính năng hơn là Kaizen Elastic

Link: https://elastic-kaizen.com/download

image.png

Tải về phiên bản phù hợp, ở đây tôi tải về bản mới nhất

Sau khi tải xong, giải nén được thư mục như hình:

image.png

Bên trong thư mục, sẽ có 1 file "kaizen.bat", chạy file này lên sẽ có giao diện:

image.png

Trên giao diện, click vào icon hình đám mây hoặc click "Server" -> click "Connect" hoặc nhấn tổ hợp phím "Alt + O":

image.png

Tại giao diện "Connections", mặc định đã có 1 host được tạo sẵn, chỉ cần click chọn host được tạo sẵn và click icon đám mây(Connect):

image.png

=> Kết nối thành công

Với những tính năng khác các bạn có thể tự tìm hiểu vì trong bài viết này tôi không đi sâu vào công cụ này

2. Cấu trúc project:

image.png

### Nội dung file "pom.xml":

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>Token</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Thymeleafs</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3. Tạo 1 package "com.example.token.application":

Nội dung class "TokenApplication":

image.png

4. Tạo 1 package "com.example.token.model":

Nội dung class "User":

image.png

Nội dung class "Token":

image.png

5. Tạo 1 package "com.example.token.repository":

Nội dung class "UserRepository":

image.png

Trong class này tôi có khai báo thêm 1 phương thức là "findByUserId", tôi muốn nhắc nhở các bạn không phải muốn đặt tên phương thức như nào cũng được

Tôi lấy ví dụ để các bạn dễ hiểu, trong class này tôi sẽ sửa lại tên phương thức "findByUserId" đến "findByPhone" và nó sẽ báo lỗi khi bạn start project:

image.png

image.png

Nguyên nhân là do khi đặt tên phương thức các bạn cần lưu ý điều này, ví dụ trong model "User" tôi không có thuộc tính tên "phone" nên khi tôi khai báo 1 phương thức với tên "findByPhone" -> lỗi

Bây giờ tôi sẽ quay lại class model "User" và thêm 1 thuộc tính là "phone":

image.png

Restart lại project và thấy không có lỗi:

image.png

Như vậy, kết luận để khai báo thêm 1 phương thức trong interface repository, cần đặt tên phương thức theo quy tắc:

Ví dụ: findBy + "tên thuộc tính có khai báo trong class model"

Nội dung class "TokenModel":

image.png

6. Tao 1 package "com.example.token.controller":

Nội dung "UserController":

Tôi sẽ tạo trước 1 mapping để load trang đăng nhập "index.html":

image.png

Restart project và truy cập url "https://localhost:8080/". Cần chú ý do trong bài viết trước tôi đã có hướng dẫn enable SSL và tạo certificate nên bài viết này tôi không nói lại, bạn nào không muốn sử dụng SSL thì vào "application.yml" và update lại giá trị "true" thành "false" cho SSL

image.png

=> Page đăng nhập load thành công

Tôi tạo 1 mapping trong controller để load page dashboard:

image.png

image.png

Với user thường không phải admin khi đăng nhập sẽ cho chuyển hướng đến page khác, ở đây là "user.html":

image.png

image.png

7. Tạo 1 package "com.example.token.service":

Nội dung class "UserService":

image.png

Nội dung interface "IUserService":

image.png

Tôi có sử dụng mã hoá Base64 cho mã hoá thông tin password khi gửi dữ liệu từ FE và khai báo 1 phương thức giúp giải mã(decode) về lại utf8. Nếu bạn không muốn sử dụng có thể tuỳ chỉnh lại code

Sau khi hoàn thành các thành phần cần thiết. Tiếp theo, tôi xử lý tự động tạo 1 token mỗi lần user login

8. Tạo token mỗi lần user login:

Tôi giả định tôi là admin và tài khoản admin của tôi đã có trong hệ thống. Nhưng tôi sẽ tạo 1 api để tạo user và dùng postman để call api này

Trong UserController tôi thêm mapping "/createUser":

image.png

Tôi mở Postman và call api "https://localhost:8080/createUser", method = "POST":

Phần body data:

image.png

Kết quả:

image.png

=> Tạo user thành công. Tôi mở Kaizen lên để kiểm tra:

image.png

Thông tin đã được tạo thành công và password được mã hoá

Tiếp theo, tôi sử dụng tài khoản admin vừa tạo để đăng nhập vào trang dashboard:

Tôi tạo 1 mapping "/login" trong controller:

image.png

Vui lòng tham khảo bài viết bên dưới tôi đã có hướng dẫn tạo function xử lý tại FE:

https://viblo.asia/p/ma-hoa-thong-tin-password-trong-qua-trinh-login-register-voi-base64-su-dung-spring-boot-thymeleaf-elasticsearch-khong-su-dung-form-bXP4WPoBJ7G

Đây là script file tôi xử lý cho login page "index.html":

image.png

Tôi tiến hành đăng nhập với tài khoản admin:

image.png

=> Login thành công

Tiếp theo, tôi sẽ tạo tự động token cho mỗi user sau khi xác thực thành công user có trong hệ thống. Trong bài viết này tôi không sử dụng JWT token hay oauth2 bởi vì tôi muốn các bản hiểu 1 cách đơn giản nhất có thể về token

Thông thường nếu không tạo token, khi bạn call 1 api bất kỳ nó sẽ không yêu cầu bạn xác thực thông tin gì cả nhưng nếu có token cho mỗi lần call api nó sẽ yêu cầu phải có token, nếu không cung cấp token hợp lệ -> failed

Trong một vài dự án dùng multiservice thì token sẽ được quản lý bởi ouath2 service và mỗi lần call api việc đầu tiên là sẽ kiểm tra token có tồn tại hay không và token đã hết hạn chưa, nếu token hết hạn -> văng lỗi

Trước tiên tôi tạo 1 phương thức sử dụng "UUID" để random ra token, tôi sẽ khai báo trong "IUserService""UserService":

Tại "IUserService" tôi khai báo:

image.png

Tại "UserService":

image.png

Tôi restart lại project và thử đăng nhập để kiểm tra token được sinh ra:

image.png

=> Token được tạo thành công

Tại UserController, phương thức "checkInfoUserLogin" với mapping "/login" tôi sửa code lại để lưu token vào database:

image.png

Restart lại project và đăng nhập lại lần nữa để kiểm tra xem token có được lưu vào database thành công không:

image.png

image.png

=> Token được lưu thành công, các bạn thấy hiện tại trong database có 2 token, do trước đó tôi đã có đăng nhập. Nếu muốn xoá record token nào thì chỉ cần click chọn record đó rồi click button "Remove"

Sau khi tạo token thành công, tôi tạo 1 function "getUser", trong function này tôi sẽ lấy giá trị token trên header để kiểm tra trong database có tồn tại không:

image.png

Tôi dùng postman để kiểm tra với 1 số kịch bản:

Kịch bản 1: Không set header

image.png

=> Trả về lỗi

Kịch bản 2: Set header nhưng nhập token không đúng

image.png

=> Trả về lỗi

Kịch bản 3: Set header với token đúng

image.png

image.png

=> Trả về data user thành công

Tiếp theo, trong model class "Token" tôi khai báo thêm 1 thuộc tính là "tokenExpiredAt", thuộc tính này dùng để lưu thời gian mà token được tạo ra, và mỗi lần call api khi check token sẽ cần kiểm tra xem token này còn hạn hay hết hạn:

image.png

Tôi khai báo 1 thuộc tính "token.expired.in" in application.yml với đơn vị tính là bằng phút. Ví dụ, tôi muốn sau 1 phút thì token mới hết hạn nghĩa là thời gian sống của token là 1 phút, tôi thiết lập giá trị như bên dưới:

token:
  expired:
    in: 1

image.png

Tôi tạo 1 phương thức để tính toán thời gian token sẽ hết hạn:

Trong IUserService:

image.png

Trong UserService:

image.png

Trong class "UserService" tôi cần lấy giá trị thuộc tính vừa tạo trong application.yml để sử dụng trong phương thức "getTokenExpiredAt":

image.png

Thời gian sống của token sẽ bằng thời gian token được tạo ra(ở đây tôi lấy theo thời gian hiện tại) + thời gian mà tôi chỉ định token này sẽ sống trong bao lâu(ở đây chính là giá trị thuộc tính khai báo trong application,yml trước đó được tính bằng phút và tôi quy đổi ra thành milisecond)

long currentTime = new Date().getTime() + TimeUnit.MINUTES.toMillis(tokenExpiredIn);

Tiếp theo, tôi tạo thêm phương thức để kiểm tra token mỗi khi user đăng nhập

Ví dụ, user đăng nhập lần 1 -> generate new token -> user không logout và close tab hiện tại -> user vào lại thì sẽ kiểm tra xem token của user này đã hết hạn chưa, nếu chưa thì không cần tạo mới token và login đến dashboard, nếu token đã hết hạn -> redirect về lại trang đăng nhập

Trong IUserService:

image.png

Trong UserService:

Tôi cần khai báo TokenRepository, tôi dùng annotation "@AutoWired":

image.png

Phương thức "checkToken":

image.png

Trong phương thức này, cần quan tâm vấn đề tính thời gian hết hạn cho token:

            long tokenExpiredAt = obj.getTokenExpiredAt();
            long currentTime = new Date().getTime();
            if(tokenExpiredAt - currentTime > 0) {
                // not expired yet
                return true;
            }else {
                // token existed but expired -> delete token expired
                // remove old token
                tokenRepo.delete(obj);
            }
  • Giá trị "tokenExpiredAt": Chính là giá trị thời gian khi token được sinh ra + thời gian sống của token
  • Giá trị "currentTime": Lấy ra thời gian hiện tại

Và để tính thời gian token hết hạn hay chưa tôi lấy "tokenExpiredAt - cuurentTime". Để cho dễ hiểu, tôi lấy ví dụ như bên dưới:

Giả sử tôi có token được sinh ra vào lúc "10:00 AM" và tôi chỉ định token sống trong 5 phút -> có nghĩa là sau "10:05 AM" token sẽ hết hạn và sau 1 khoảng thời gian 6 phút thì thời gian hiện tại là "10:06 AM", theo công thức tính ở trên:

Lấy "10:05 AM" - "10:06 AM" -> giá trị sẽ nhỏ hơn 0 -> token hết hạn

Tiếp theo, sau khi tạo phương thức "checkToken", tôi tạo tiếp 2 phương thức "createCookie""getValueCookie" , lưu giá trị "token" và "tokenExpiredAt" tại cookie, lý do tôi sẽ nói ở phần sau:

Phương thức "createCookie":

Trong "IUserService":

image.png

Trong "UserService":

image.png

Phương thức "getValueCookie":

Trong "IUserService":

image.png

Trong "UserService":

Tôi cần khai báo "HttpServletRequest":

image.png

image.png

Sau khi chuẩn bị xong, tôi quay lại UserController và sửa lại phương thức "checkInfoUserLogin" với mapping name "/login":

image.png

Bây giờ, tôi restart lại project mà kiểm tra với 1 số kịch bản:

Kịch bản 1: User đăng nhập lần đầu -> tạo new token, trước tiên tôi kiểm tra database xem có token nào không:

image.png

=> Không có token nào

Tôi tiến hành đăng nhập với user "admin"

image.png

=> Token và "tokenExpiredAt" được thêm vào cookie thành công

Kiểm tra database:

image.png

=> "Token" và "tokenExpiredAt" được lưu thành công

Kịch bản 1: User close tab và mở lại -> sẽ kiểm tra token hết hạn hoặc chưa, ở đây tôi đang chỉ định token sống trong 1 phút

Tôi thử đăng nhập lại vào page dashboard -> sẽ check token, tôi xử lý thêm tại mapping "/dashboard":

image.png

Tôi lấy giá trị token được lưu tại cookie trước đó và gọi function kiểm tra token để kiểm tra:

image.png

=> Sau khi token hết hạn sẽ bị remove ra khỏi database

Tiếp theo, tại trang dashboard admin tôi xứ lý tiếp tính năng như Thêm - Xoá - Sửa user:

image.png

Đây là giao diện dashboard dành cho admin, tại page này tôi sửa lại thông tin 1 vài field cho phù hợp với User model của tôi

image.png

Sau khi thay đổi, tôi có 6 fields là "UserId"(required) - "Email" - "First Name"(required) - "Last Name" - "Address" - "Birth Day"(required)

Trước khi đi vào xử lý các chức năng Thêm - Xoá - Sửa user, tôi tạo thêm 2 package "com.example.token.filter""com.example.token.config" cho mục đích filter tất cả request url:

Trong package "com.example.token.filter":

Tôi tạo 1 class "UserFilter" với annotation "@Component":

image.png

Trong class "UserFilter" tôi khai báo 3 thành phần "HttpServletRequest" - "HttpServletResponse" - "IUserService" và tôi implements "Filter", tôi chỉ cần sử dụng phương thức "doFilter" để đọc tất cả request gửi đến:

image.png

**Trong phương thức "doFilter" tôi chỉ lọc 3 mapping tương ứng với Thêm - Xoá - Sửa và xem thông tin user": **

  • "/updateUser" để xử lý cho cập nhật và tạo mới user
  • "/getUser" để xử lý xem thông tin user
  • "/deleteUser" để xử lý xoá user

Ở đây tôi dùng "startsWith" nghĩa là nếu request url gửi đến có dạng " /getUser/** " -> đều được đi vào

Sau khi tạo xong class UserFilter, tôi tạo tiếp class UserConfig trong package "com.example.token.config":

image.png

Xong phần chuẩn bị tại BE, tôi qua FE và tạo 1 script file "script.js" trong thư mục "static" để xử lý phần gửi data đến BE và thêm token trong request headers. Tại html page "dashboard.html" tôi thêm script file "script.js":

image.png

Cấu trúc project:

image.png

Trong script file, tôi cần tạo 3 phương thức chính:

  • getCookie(): Trong phần trên tôi đã thêm token vào cookie nên tại đây khi gửi data đến BE tôi cần lấy ra giá trị token này để kiểm tra token hết hạn hoặc không tại BE

image.png

Tham khảo thêm về cookie tại đây: https://www.w3schools.com/js/js_cookies.asp

  • getToken(): Phương thức chỉ để trả về giá trị token từ phương thức ở trên, tôi không muốn dùng chung với "getCookie()"

image.png

  • updateUser(): Phương thức này để validate các fields bắt buộc, gửi data đến BE và sau khi lấy được token từ cookie -> thêm 1 header với định dạng {"Authorization": "Bearer " + token} hoặc {"Authorization":token} hoặc với bất kỳ tên nào miễn là có thể lấy ra giá trị token trong request headers

image.png

Cập nhật phương thức "updateUser()" tại button "Save changes" trong "dashboard.html":

image.png

Trong phương thức "updateUser" có 3 vấn đề quan trọng:

  • Validate data, có 3 fields bắt buộc cần validate là "UserId" - "First Name" - "Birth Day":

image.png

Ở đây tôi đã tạo 3 html tag với nội dung "<span style="color:red" name = "message"></span>" tại 3 vị trí fields cần validate:

image.png

  • Tạo 1 password theo 1 pattern cụ thể: "P@ssword" + "birthDate"(yyyymmdd). Ví dụ: user có birthDate là 01-01-1990 -> password sẽ là "P@ssword19900101":

image.png

  • Gửi data đến BE, tại đây tôi lấy ra giá trị token lưu trong cookie từ phương thức "getToken()" và add headers đến request headers:

image.png

Vậy là phần chuẩn bị tại FE đã xong, tôi sẽ kiểm tra 1 kịch bản tại FE cho trường hợp validate data:

Tôi bỏ trống những fields bắt buộc và click button "Save changes", kiểm tra kết quả:

image.png

image.png

=> Validate data thành công

Tiếp theo, xử lý tại BE cho Thêm và Cập nhật user:

Thêm - Cập nhật User:

Tại UserController tạo phương thức "updateUser":

image.png

Tiến hành kiểm tra cho kịch bản tạo mới user:

image.png

=> Tạo mới user thành công

Tiếp theo, tôi kiểm tra cho kịch bản nếu token user admin hết hạn -> sẽ không thể call đến api "updateUser" và văng lỗi "401". Tôi chờ cho qua 1 phút bởi vì tôi chỉ định thời gian token sống là 1 phút:

image.png

=> Cho lần thứ 2 call api "updateUser" -> token expired -> văng lỗi

Lần thứ 3:

image.png

Kiểm tra database:

image.png

=> User mới được thêm thành công

Tôi thử đăng nhập với user vừa tạo(user thường) -> sẽ không thể load trang dashboard admin:

image.png

=> Với user thường sẽ chỉ load page "user.html"

Kiểm tra database với token được tạo mới:

image.png

=> Token được tạo mới và lưu thành công

Phương thức "getUserPage" mapping "/user":

image.png

Tiếp theo, tôi qua tính năng Xoá user:

Xoá thông tin User:

Thêm phương thức "deleteUser()" trong script file:

image.png

Khai báo phương thức này trong html:

image.png

Tạo 1 phương thức "deleteUser" với mapping "/deleteUser" trong UserController:

image.png

Kiểm tra với kịch bản delete user không tồn tại:

image.png

=> User này không có trong system nên sẽ báo lỗi

Kiểm tra với kịch bản delete user đã có:

image.png

=> User deleted success

Kiểm tra với kịch bản delete user nhưng token hết hạn:

image.png

=> Trả về lỗi 401

Tiếp theo, tôi xử lý thêm 1 vài tính năng nâng cao, tại FE tôi tạo 1 function trigger sau thời gian chỉ định call đến BE để xin cấp mới token

Ví dụ, tôi đăng nhập và token được tạo ra với thời gian sống là 2 phút, thì tôi xử lý tại FE sau thời gian 1 phút sẽ tự động call đến BE để xin cấp mới token, nghĩa là khi token còn 1 phút nữa là hết hạn thì functione sẽ được gọi để call đến BE

Tạo 1 function tự động tại FE sau một thời gian nhất định call đến BE để xin cấp mới token:

Trước tiên tôi tạo 1 mapping xử lý việc xin cấp mới token tại BE UserController, các bạn có thể tạo riêng 1 controller khác như "TokenController" cho xử lý chỉ về token để dễ quản lý:

image.png

Tiếp theo, tôi tạo 1 phương thức trong script file:

image.png

Các phần xử lý chính:

  • Lấy ra giá trị "tokenExpiredAt" tại cookie(milisecond)

  • Lấy giá trị thời gian hiện tại(milisecond)

  • Thời gian thực thi, tôi dùng công thức như bên dưới:

      let executeAfter = Number(tokenExpiredAt) - Number(currentTimeInMillis) - 60 * 1000;
    

Tôi lấy ví dụ cho dễ hiểu công thức trên:

Ví dụ: Tôi đăng nhập và vào thời điểm "09:00 AM" token được tạo và tôi chỉ định token này sống trong 2 phút -> thời gian hết hạn của token(tokenExpiredAt) sẽ vào khoảng "09:02 AM lẻ 2 giây". Để tính ra thời gian thực thi, tôi lấy giá trị "tokenExpiredAt" là "09:02 AM" - thời gian hiện tại ví dụ là "09:00 AM lẻ 10 giây", thời gian thì chắc chắn có chênh lệch tầm 1-2s. Và theo công thứ ở trên sẽ là:

"09:02 AM lẻ 2 giây" - "09:00 AM lẻ 10 giây" - 60*1000

Ở đây 60 chính là 60 giây và tôi muốn quy đổi ra thành milisecond -> tôi lấy 60 * 1000

Ta có thể tính rợ theo phút như: 2phút - 0phút - 1phút = 1 phút => nghĩa là sau 1 phút(thực sự khoảng 58-59 giây) nữa phương thức "extendToken" sẽ được gọi để thực hiện việc request BE generate 1 token mới

Tôi tiến hành kiểm tra cho kịch bản xin cấp mới token khi token còn khoảng 1 phút nữa là hết hạn:

Sau khi đăng nhập thành công, kiểm tra thông tin token:

image.png

Thời gian thực thi tính bằng milisecond, tôi có in ra giá trị này:

image.png

Sau thời gian 1 phút, phương thức "extendToken" được thực thi:

image.png

Tôi kiểm tra lại database xem dữ liệu đã được cập nhật lại chưa:

image.png

=> Dữ liệu được cập nhật thành công

Tôi kiểm tra lại xem cookie đã được cập nhật giá trị mới chưa:

image.png

=> Cookie không cập nhật lại giá trị token mới mặc dù tôi đã create cookie. Kiểm tra lại phương thức "createCookie":

Phương thức "createCookie":

image.png

Trong phương thức "extendToken" tôi đã gọi lại phương create cookie nhưng tại browser nó không cập nhật lại theo giá trị mới:

image.png

Để xử lý vấn đề này, tôi thêm khai báo "path" khi tạo cookie:

image.png

Bây giờ, tôi restart lại project và kiểm tra lại xem cookie có cập nhật lại giá trị mới chưa:

image.png

Database lưu dữ liệu thành công và đường dẫn "path" được cập nhật mới

Sau 1 phút, phương thức "extendToken" thực thi:

image.png

Kiểm tra lại thông tin cookie:

image.png

=> Được cập nhật thành công

Như vậy xong phần xử lý để tự động call request BE cấp mới token, phương thức "extendToken" sẽ call liên tục cứ sau mỗi 1 phút:

image.png

Để tối ưu, tôi có cập nhật lại 1 số phương thức chính:

UserController:

1. Phương thức "updateUser": Dùng chung cho cả tạo mới và cập nhật user

image.png

2. Phương thức "deleteUser":

image.png

3. Phương thức "checkInfoUserLogin": Dùng để xử lý khi user đăng nhập:

image.png

4. Phương thức "getDashboardPage": Dùng để xử lý khi load dashboard page:

image.png

5. Phương thức "extendToken": Dùng để xử lý khi FE gửi request cấp mới token:

image.png

IUserService:

image.png

UserService:

image.png

image.png

UserFilter:

image.png

FE - Nội dung script file:

image.png

1. Phương thức "requestData": Dùng để xử lý khi user đăng nhập và đăng ký. Cho phần đăng ký tôi có hướng dẫn trong bài viết trước, bài viết này tôi không sử dụng phương thức đăng ký

image.png

2. Phương thức "updateUser": Dùng để xử lý cho cả 2 tạo mới và cập nhật user

image.png

3. Phương thức "deleteUser": Dùng để xử lý cho xoá thông tin user

image.png

4. Phương thức "extendToken": Dùng để xử lý tự động trigger call request BE cấp mới token

image.png


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí