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

Login with Jwt

0 0 25

Người đăng: Nguyên

Theo Viblo Asia

bài viết trước mình đã mô tả về Jwt, tiếp theo đây hãy cùng tạo ra 1 function login đơn giản ✌️

1. Gem Jwt

gem "jwt"

Được recommended trên jwt.io, hỗ trợ đầy đủ mọi tính năng để hoàn thiện đoạn mã Jwt:

image.png

Cơ bản sẽ focus vào 3 yếu tố:

  • payload
  • SECRET_KEY_BASE
  • algorithm

Đến với payload, gửi lên những thông tin để xác thực user Ex: role, email, login_token (tương tự như session mà user đó đang sử dụng)

def payload { user_id: ..., login_token: ..., role: ..., email: ..., iat: ..., exp: ... }
end

Về phần SECRET_KEY_BASE ứng với secret_key của Jwt, chuỗi này sẽ được gen tự động trong Rails app mỗi khi khởi tạo và được sở hữu bởi người dựng app (gồm 1 cặp file master.key và credentials.yml.enc).

Lưu ý:

Tuy nhiên nếu sử dụng function Rails.application.secret_key_base để lấy chuỗi secret_key_base thì lên production sẽ bị lỗi do cặp file nhắc tới trước đó sẽ không tồn tại.

image.png Dựa vào function được định nghĩa trên github, secret_key_base sẽ ưu tiên sử dụng biến ENV trước nên sẽ bớt phức tạp và không cần phải config lại production nếu sử dụng biến ENV["SECRET_KEY_BASE"] ở mọi môi trường.

Cuối cùng là algorithm, tùy vào yêu cầu của mỗi dự án mà chọn 1 algorithm thích hợp Ex: HS256, ES512, ...

def access_token JWT.encode payload, ENV["SECRET_KEY_BASE"], Settings.jwt.algorithm
end

2. Trích xuất Jwt-Authorization từ request headers

JwtAuthorization, Jwt-Authorization hoặc bất kì cái tên nào bạn nghĩ ra và phù hợp (Hạn chế sử dụng Authorization sẽ gây ra nhầm lẫn với Basic Authen). Trong ví dụ dưới đây, key mình chọn là Jwt-Authorization ( Rails config exception )

def load_jwt_token header = request.headers["HTTP_JWT_AUTHORIZATION"] # Header được extract sẽ có dạng HTTP_xxx raise UnauthorizedRequest unless header.is_a?(String) jwt_authorization = header.split valid_token_type = jwt_authorization.first == "Bearer" # Token type jwt_token = jwt_authorization.last # Chuỗi Jwt raise UnauthorizedRequest unless valid_token_type && jwt_token.present? jwt_token
end

Tiếp theo là bước verify lại token mình vừa nhận được và load info định danh của request đó:

def decoded_token @decoded_token ||= JWT.decode token, ENV["SECRET_KEY_BASE"], true, {algorithm: Settings.jwt.algorithm}
end

Trả về của decoded_token sẽ là payload được truyền vào

def load_request_info @current_user = User.find_by id: decoded_token[0]["user_id"] @current_session = current_user.user_logins.find_by login_token: decoded_token[0]["login_token"] # Ứng với trường hợp login nhiều device -> login_token được lưu ở bảng trung gian gọi là user_login  # Bên cạnh đó việc lưu login_token ở bảng trung gian sẽ đơn giản hơn cho việc mở rộng thành login dưới dạng 1 device # Tương tự với cách vận hành của gem "doorkeeper", khi user login vào app ta sẽ revoke tất cả các sessions trước đó
end

Trong quá trình decode nếu có lỗi xảy ra sẽ được raise lên dưới mã JWT::DecodeError. Trong một vài trường hợp cần phân biệt rõ ràng giữa các lỗi như là Jwt::ExpiredSignature, Jwt::DecodeError thì ta rescue như sau:

def load_request_info ...decoded_token... rescue Jwt::ExpiredSignature ... rescue Jwt::DecodeError ... end
end

Lưu ý:

Không thể đặt Jwt::DecodeError lên đầu vì là class cha của Jwt::ExpiredSignature

3. Test với postman

Call API login với user đã generate từ trước -> image.png

Sau đó mỗi lần client call request thì đính kèm Jwt-Authorization vào header ->

image.png

4. Kết luận

Happy coding! Make awesome thing today :v

Bình luận

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

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

Giới thiệu về Hash trong Ruby và Rails

. Hash là một cấu trúc dữ liệu lưu trữ bằng các khóa liên quan. Điều này trái ngược với array lưu trữ các mục theo một chỉ mục có thứ tự.

0 0 27

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

3 cách tạo ra class methods private trong Ruby

. Bài viết được dịch từ bài 3 ways to make class methods private in Ruby của tác giả Mehdi Farsi. . . private_class_method.

0 0 26

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

Ghi đè phương thức private của superclass trong Ruby

. Bài viết được dịch từ bài Overriding private methods of superclass in Ruby của tác giả Mehdi Farsi. Vì Ruby là một ngôn ngữ OOP, một class có thể kế thừa từ một class khác.

0 0 17

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

Asset Pipeline là cái chi chi?

Asset Pipeline. Asset pipeline là cái chi chi. . Giải thích:.

0 0 47

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

Cùng xây dựng app Ajax đơn giản trong Rails

Chúng ta cùng thử viết một Web app đơn giản có sử dụng Ajax bằng Ruby on Rails nhé! . Trong bài viết mình sẽ nói thẳng vào cách xây dựng ajax luôn nên nếu các bạn chưa nắm được cách viết 1 app CRUD bằ

0 0 27

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

[Ruby] Tìm hiểu kế thừa trong ruby

Chắc hẳn mỗi người trong chúng ta khi học hay làm việc thì đã nghe đến khái niệm kế thừa. .

0 0 24