TokenMismatchException in VerifyCsrfToken.php được xem là lỗi thường gặp nhất đối với các bạn mới làm quen thiết kế web với framework Laravel. Có nhiều nguyên nhân dẫn đến lỗi này, thông thường nhất đó chính là các bạn quên đặt csrf_token() vào form, khi submit Laravel sẽ báo lỗi thiếu Token.
Tuy nhiên, một số trường hợp đã cài đặt csrf_token() ở form hoặc ở thẻ meta, nhưng thỉnh thoảng vẫn xuất hiện lỗi cứng đầu này, xin mời hãy tham khảo hướng dẫn dưới đây mà qua quá trình làm việc với Laravel Trungtrinh.com đã tìm ra và đã có cách khắc phục.
Các bạn hãy làm theo các cách dưới đây, làm từ cách 1, nếu không khắc phục được thì làm từ từ xuống các cách phía dưới nhé.
Đây được coi là lỗi sơ đẳng, muôn thuở muôn đời phổ biến nhất, đó là quên cài csrf_token() vào form hoặc thẻ meta.
Các bạn hãy kiểm tra kỹ xem form cần submit đã có chèn đoạn code dưới đây chưa, nếu chưa, thì quá đơn giản, chèn nó vào đầy thẻ <form....> là được:
<input type="hidden" name="_token" value="{{ csrf_token() }}">
Hoặc để cho khỏi quên mỗi khi thêm một form mới, các bạn hãy chèn hẳn lên Header thẻ meta như sau:
<meta name="csrf-token" content="{{ csrf_token() }}" />
Sau khi chạy web, các bạn Viewsource xem nếu có một trong hai dòng dưới đây thì xem như là đã ok:
<input type="hidden" name="_token" value="iNLkscqedNzzBBCdbgZixayIljgfc7PIIxFaUH7t">
<meta name="csrf-token" content="FBGqmBNGR8LanwzqSCZtFlYwbjjTRHf72gxo3thq" />
Session là gì?
Session là một phiên làm việc là một khái niệm phổ biến được dùng trong lập trình web có kết nối với database. Đặc biệt các chức năng như đăng nhập, đăng xuất người dùng sẽ khó có thể thực hiện được nếu không sử dụng session.
Ở Laravel, Mỗi form làm việc sinh ra một Token tương ứng với một Session, Session có một thời gian nhất định, khi quá thời gian trên, Token xem như cũng hết hạn, chính vì thể một số trường hợp khách truy cập vào form để điền thông tin nhưng để lâu quá mới bấm Submit, lúc đó Token hết hạn và xảy ra lỗi TokenMismatchException in VerifyCsrfToken.php
Vậy, cách để khắc phục vấn đề này, đó là tăng thời gian hiệu lực của Session lên. Mặc định thì thời gian hiệu lực Laravel setup sẵn là 120 phút, được cấu hình ở file config/session.php.
Để điều chỉnh thời gian tăng lên, các bạn hãy sửa số 120 thành một số khác, đơn vị sẽ là phút.
Phần 'expire_on_close' => false cũng là một trường hợp quan trọng, đây là tùy chọn kết thúc phiên khi đóng trình duyệt. Có một số khách truy cập sau khi đóng trình duyệt, phiên làm việc vẫn tính, và khi mở lại ở thời điểm sắp hết Session thì thời gian còn lại để submit form quá ít, dẫn đến lỗi TokenMismatchException. Cách khắc phục đơn giản, đó là các bạn hãy sửa giá trị thành true, như vậy sau khi điều chỉnh, kết quả sẽ như sau: (số phút là tùy chọn của các bạn)
Một số trường hợp, vì cấu trúc code, hoặc vì ảnh hưởng của cấu hình PHP, server,.... mà cài đặt lifetime trong file config/session.php không được sử dụng, dẫn đến thời gian thực của Session nhanh hơn do với cài đặt, trường hợp này, các bạn hãy thêm dòng dưới đây vào file .ENV
SESSION_LIFETIME=120
Khi Token hết hạn (hết phiên làm việc), nếu là kỹ thuật thì sẽ biết cách khắc phục đó là refesh lại trang, Token mới sẽ được sinh ra. Tuy nhiên, đối với khách truy cập, không phải ai cũng biết điều này, vậy cách khắc phục là gì? Đó chính là code cho Client tự động tạo Token mới sau khoảng thời gian nhất định, Trung trịnh .com đã tìm hiểu và test thử và kết quả hơn cả mong đợi.
Với cách này, các bạn hãy đặt csrf_token() vào thẻ meta. Sau đó hãy thêm đoạn srcipt sau vào đầu thẻ <body>
<script type="text/javascript">
var csrfToken = $('[name="csrf_token"]').attr('content');setInterval(refreshToken, 3600000); // 1 hour
function refreshToken(){
$.get('refresh-csrf').done(function(data){
csrfToken = data; // the new token
});
}setInterval(refreshToken, 3600000); // 1 hour
</script>
Sau đó hãy thêm vào Router:
Route::get('refresh-csrf', function(){
return csrf_token();
});
GIẢI THÍCH:
Lệnh setInterval(refreshToken, 3600000); sẽ set sau mỗi giờ thì thực hiện hàm refreshToken.
Hàm refreshToken sẽ get một router có tên refresh-csrf thực hiện tạo ra một Csrf_token mới và gán cho giá trị của thẻ meta có tên csrf_token.
Như vậy, với cách này, sau mỗi giờ Token sẽ tự động refesh mà không cần phải refesh lại trình duyệt, có thể khắc phục được lỗi TokenMismatchException in VerifyCsrfToken.php
Có một số lý do, chẳng hạn như bảo mật, không thể tăng thêm thời gian làm việc của phiên, cách này Trung Trịnh nghĩ ra theo suy nghĩ cá nhân, nếu không hợp lý các bạn đừng ném đá nhé, ahihi, cách tối ưu nhất đó là thông báo lỗi cho người dùng biết đã hết phiên làm việc, và hãy refesh lại trình duyệt.
Các bạn mở file app/Exceptions/Handler.php, kéo xuống hàm public function render, và thêm vào trước Return đoạn code sau:
if ($e instanceof \Illuminate\Session\TokenMismatchException) {
return redirect('/trang-bao-loi')->withErrors(['token_error' => 'Trung Trịnh .Com xin lỗi! phiên làm việc của bạn đã hết hạn, vui lòng thử lại.']);
}
"trang-bao-loi" chính là đường dẫn web sẽ chuyển hướng đến, và hiển thị lỗi thông báo đến người dùng, các bạn có thể điều hướng sang trang chủ bằng cách để "/" hoặc refesh lại chính trang hiện tại bằng cách điền URL của nó vào.
Ở trang báo lỗi, các bạn cần chèn đoạn mã dưới đây vào View:
@if ($errors->has('token_error')) {{ $errors->first('token_error') }} @endif
Như vậy, trên đây là tổng hợp 4 cách xử lý lỗi TokenMismatchException in VerifyCsrfToken.php mà Trung Trịnh .Com đã thực hành qua và cảm thấy là tốt nhất. Nếu các bạn còn giải pháp nào tối ưu hơn, hãy comment bên dưới để mọi người cùng tham khảo nhé.
Bạn đang xem bài viết tại chuyên mục Laravel của Website Trung Trịnh. Nếu thấy bổ ích, hãy bấm like và share để chia sẻ cho mọi người cùng xem nhé!