How Rails Sessions Work

I. Tổng quan

Điều gì nếu ứng dụng Rails của bạn không thể đưa ra thông tin người đã ghé thăm nó? Nếu bạn không có ý tưởng rằng cùng một người yêu cầu hai trang khác nhau? Nếu tất cả các dữ liệu bạn lưu trữ biến mất ngay sau khi bạn được phản hồi lại?

Đó có thể là tốt cho một trang web tĩnh. Nhưng hầu hết các ứng dụng Web cần có thể lưu trữ được một số dữ liệu về người dùng. Có lẽ đó là một id người dùng, hoặc một ngôn ngữ ưa thích, hoặc cho họ luôn luôn nhìn thấy các phiên bản desktop của trang web của bạn trên iPad của họ. Session là nơi hoàn hảo để đưa loại dữ liệu này. Một vãi dữ liệu mà bạn muốn giữ lại chứ không chỉ đơn giản là một request.

Ví dụ về session:

session[:current_user_id] = @user.id

Nhưng chúng có một điều gì đó khá thú vị và kì diệu mà tôi sẽ nói tới trong bài viết dưới đây. Trước hết, ở phần đầu tiên, tôi sẽ nói cho các bạn hiểu thế nào là session và session trong ứng dụng Rails. Ở phần tiếp theo, các bạn sẽ được biết về các sử dụng session trong Rails app cũng như những lợi ích của việc sử dụng session. Ngoài session, ở phần sau đó, tôi sẽ giới thiệu về các giải pháp thay thế nếu bạn không sử dụng session để lưu trữ dữ liệu.

II. Session là gì?

Session là được hiểu là 1 phiên làm việc trong đó người sử dụng giao tiếp với 1 ứng dụng. Session bắt đầu khi người sử dụng truy cập vào ứng dụng lần đầu tiên, và kết thúc khi người sử dụng thoát khỏi ứng dụng. Một session thường được gắn với 1 mã số định danh (Session ID) và 1 hash chứa 1 số thông tin nhất định của người dùng. Trong ngữ cảnh ứng dụng web, đó có thể là định danh của người dùng, những bài viết mà người đó đã đọc qua hay những món hàng mà người đó đã xem và có ý định mua…

Bạn có thể thiết lập dữ liệu trong một controller:

app/controllers/sessions_controller.rb
def create
  # ...
  session[:current_user_id] = @user.id
  # ...
end

Và đọc nó ra từ một controller khác:

app/controllers/users_controller.rb
def index
  current_user = User.find_by_id(session[:current_user_id])
  # ...
end

Nó dường như khá thú vị. Nhưng nó cần sự phối hợp giữa trình duyệt của người dùng với ứng dụng Rails để chúng được kết nối với nhau. Và tất cả chúng bắt đầu với cookies. Khi bạn yêu cầu 1 trang Web, server có thể gán 1 cookie khi nó phản hồi lại. ~ jweiss$ curl -I http://www.google.com | grep Set-Cookie

Set-Cookie: NID=67=J2xeyegolV0SSneukSOANOCoeuDQs7G1FDAK2j-nVyaoejz-4K6aouUQtyp5B_rK3Z7G-EwTIzDm7XQ3_ZUVNnFmlGfIHMAnZQNd4kM89VLzCsM0fZnr_N8-idASAfBEdS; expires=Wed, 16-Sep-2015 05:44:42 GMT; path=/; domain=.google.com; HttpOnly

Trình duyệt của bạn sẽ lưu trữ những cookies đó. Và chó tới khi cookies hết hạn, mỗi lần bạn tạo một request tới server, trình duyệt của bạn sẽ gửi cookies trả lại server. ...

> GET / HTTP/1.1
> User-Agent: curl/7.37.1
> Host: www.google.com
> Accept: */*
> Cookie: NID=67=J2xeyegolV0SSneukSOANOCoeuDQs7G1FDAK2j-nVyaoejz-4K6aouUQtyp5B_rK3Z7G-EwTIzDm7XQ3_ZUVNnFmlGfIHMAnZQNd4kM89VLzCsM0fZnr_N8-idASAfBEdS; expires=Wed, 16-Sep-2015 05:44:42 GMT; path=/; domain=.google.com; HttpOnly
...

Nhiều cookies chúng ta thấy dường như nó vô nghĩa. Và họ cho rằng như vậy. Bởi vì thông tin về cookies là không có nghĩa đối với người dùng. Ứng dụng Rails của bạn phụ trách định hình ý nghĩa của cookies là gì.

III. What does this have to do with a session?

Vì vậy, nếu bạn có 1 cookie và bạn thiết lập dữ liệu trong suốt quá trình gửi request, và bạn lấy về dữ liệu giống với lần tiếp theo đó. Vậy điều khác biệt giữa cookie ở trên và session là gì? Với ứng dụng Rails, mặc định của nó thì sự khác biệt là không nhiều. Rails làm một vài việc với cookies để đảm bảo tính bảo mật cho ứng dụng. Nhưng bên cạnh đó, nó cũng làm việc như cách mà bạn mong đợi. Ứng dụng Rails của bạn đặt một số dữ liệu của bạn bên trong cookies, những dữ liệu này là giống nhau ở kết quả trả về của cookie. Nếu những điều trên đúng thì chúng ta không có lỹ do gì để phân biệt giữa cookie và session.

  • Bạn có thể lưu trữ khoảng 4kb dữ liệu trong 1 cookie. Trong một số trường hợp nó là thiếu với một lượng dữ liệu lớn.
  • Cookies được gửi đi ở bất kì request nào của bạn tạo ra. Lượng cookies lớn có nghĩa là request và response là khổng lồ, điều đó làm website của bạn chậm hơn.
  • Nếu bạn vô tình làm lộ secret_key_base của bạn, người dùng có thể thay đổi dữ liệu bên trong cookies của bạn. Đặc biệt khi bạn có chứa thông tin về current_user, nếu bị thay đổi thì ai cũng có thể làm gì họ muốn.
  • Lưu trữ sai kiểu dữ liệu trong cookie có thể bị thiếu tính bảo mật. Nếu bạn không cẩn thận, đó thực sự là một vấn đề lớn.

Nhưng nếu bạn không lưu trữ dữ liệu session của bạn bên trong cookie vì một vài lý do, Rails có một và biện pháp thay thế cho bạn.

IV. Alternative session stores

Nếu bạn muốn track sessions của bạn với ActiveRecord:

  1. Khi bạn gọi session[:current_user_id] = 1 trong app Rails, và một session của bạn không tồn tại.
  2. Rails sẽ tạo ra 1 bản ghi mới bên trong bảng sessions cảu bạn với 1 session ID ngẫu nhiên (vd: 09497d46978bf6f32265fefb5cc52264)
  3. Nó sẽ lưu trữ {current_user_id: 1}(Base64-encoded) bên trong thuộc tính của bản ghi.
  4. Và nó sẽ trả về session ID đã được sinh ra ở trên để trình duyệt sử dụng Set-Cookie.

Lần tiếp theo bạn request một trang web.

  1. Trình duyệt sẽ gửi cookie giống như vậy tới ứng dụng của bạn, sử dụng Cookie: header. (ví dụ: Cookie: _my_app_session=09497d46978bf6f32265fefb5cc52264; path=/; HttpOnly)
  2. Khi bạn gọi session[:current_user_id]:
  3. Ứng dụng của bạn sẽ lấy session ID cookie của bạn, và tìm bản ghi tương ứng của nó đã lưu trữ trong bảng session.
  4. Và nó sẽ trả về current_user_id như 1 giá trị thuộc tính của bản ghi.

Và còn một số cách lưu trữ nữa mà tôi sẽ trình bày ở bài viết sau How Rails Sessions Work[Part2] cũng như trình bày khi nào chúng ta nên lưu trữ sesion