Không lưu phân quyền vô cookie, chỉ nên sử dụng cookie cho việc đăng nhập lại sau khi session hết hạn.
Không nên dùng captcha để bảo mật form. Đúng là có tác dụng thật, nhưng sẽ gây phiền phức cho người dùng.
Mình sẽ ví dụ cho bạn mẫu mình hay dùng, mẫu này đã được tối giản để bạn dễ theo dõi.
Database
-
Roles: id, name
Dùng để chia cấp bậc như Admin, Manager, Member.
-
Users: id, id_role, username, password
Thông tin người dùng.
-
RememberTokens: id_user, token, user_agent
Lưu token sau khi đăng nhập thành công.
-
Permissions: id_role, controller, action
Xác định quyền theo cấp bậc.
Đăng nhập lần đầu
Khi người dùng đăng nhập thành công, bạn lấy username
+ password
+ user_agent
(thông tin trình duyệt) và mã hóa chúng để tạo token
, có thể dùng md5 để mã hóa.
Lưu vào cookie id_user
và token
vừa tạo. Đồng thời cũng ghi vào RememberTokens.
Tạo session auth
chứa id_user
và id_role
.
Phân quyền bằng ACL
ACL có thể lưu trong cache là tốt nhất, nếu không được thì lưu thành file, dù sao vẫn sẽ tốt hơn truy cập vào database.
Khi chưa có ACL thì bạn truy cập Permissions để lấy và tạo ACL chứa toàn bộ dữ liệu của nó. Ví dụ thế này:
admin|products|seach
admin|products|create
admin|products|update
admin|products|delete
manager|products|seach
manager|products|create
manager|products|update
member|products|seach
Khi người dùng thực hiện thao tác nào đó ta sẽ có được controller
và action
, thêm id_role
trong session nữa là đủ để bạn so sánh với ACL. Nếu không tồn tại trong ACL thì cấm hết.
Đăng nhập trở lại bằng cookie
Session hết hạn, và cookie vẫn còn.
Lấy id_user
từ cookie, kiểm tra tồn tại trong Users và lấy được thông tin người dùng.
Dùng username
và password
vừa lấy, cộng thêm user_agent
của trình duyệt hiện tại là bạn tạo được token
.
Kiểm tra token
vừa tạo đó với cái đang lưu trong cookie.
Có được token
và id_user
rồi thì kiểm tra RememberTokens.
Khi các thông tin đã đúng thì tạo lại session auth
.
Đăng xuất
Người dùng đăng xuất thì xóa cookie, session và dữ liệu trong RememberTokens.
Chống CSRF
Tạo chuỗi ngẫu nhiên mỗi khi nhập form, đồng thời ghi vào form nhập liệu của người dùng. Ví dụ: abcXYZ
<input type="hidden" name="token" value="abcXYZ">
Khi người dùng gửi request thì kiểm tra token
, đồng thời xóa nó khỏi session.
Ví dụ đơn giản để bạn hình dung, chứ thực tế không nên dùng như vậy. Ngoài token
người ta còn tạo thêm session token_time
giới hạn thời gian. Còn token
thì dùng các hàm băm như bcrypt để mã hóa, bạn sẽ có 2 chuỗi token
khác nhau cho session và form, an toàn hơn.
Hiểu nguyên tắc thì có thể viết được, nhưng bạn nên dùng các thư viện đã được nhiều người kiểm chứng. Vừa bảo mật, vừa tránh được vấn đề hiệu suất.