Giới thiệu
- Middleware là những đoạn mã trung gian nằm giữa các request và response. Nó nhận các request, thi hành các mệnh lệnh tương ứng trên request đó. Sau khi hoàn thành nó response (trả về) hoặc chuyển kết quả ủy thác cho một Middleware khác trong hàng đợi.
- Middleware như là một cơ chế cho phép bạn tham gia vào luồng xử lý request của một ứng dụng Laravel. Trong một quá trình xử lý route điển hình của Laravel khi thực thi việc xử lý yêu cầu và middleware là một trong những class mà ứng dụng phải thông qua.
- VD: middleware Authenticate có tác dụng kiểm tra xem người dùng đang thực thi request đã đăng nhập hay chưa? Nếu chưa đăng nhập thì sẽ redirect về trang login và ngược lại đăng nhập rồi thì sẽ cho phép thực hiện request.
1.Khởi tạo Middleware
Để tạo 1 middleware mới chúng ta có thể sử dụng câu lệnh sau:
1 2 | php artisan make<span class="token punctuation">:</span>middleware EnsureTokenIsValid |
Lúc này Laravel sẽ sinh ra cho bạn một file middleware nằm trong thư mục app/Http/Middleware
với tên file là tên class middleware là EnsureTokenIsValid:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">AppHttpMiddleware</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Closure</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">EnsureTokenIsValid</span> <span class="token punctuation">{</span> <span class="token comment">/** * Handle an incoming request. * * @param IlluminateHttpRequest $request * @param Closure $next * @return mixed */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Closure</span> <span class="token variable">$next</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token variable">$request</span><span class="token operator">-></span><span class="token function">input</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'token'</span><span class="token punctuation">)</span> <span class="token operator">!==</span> <span class="token string single-quoted-string">'my-secret-token'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'home'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
Trong middleware này bạn có thể thấy nếu token gửi lên từ request không khớp với token đã có thì request sẽ redirect về màn hình home. Ngược lại nếu thoả mãn thì nó sẽ cho phép request được tiếp tục
- Middleware có thể được thực thi trước hoặc sau khi request được xử lý. Như ở ví dụ trên là Middleware thực thi trước khi xử lý request tiếp theo. Còn sau đây là ví dụ về việc thực thi sau khi request được xử lý:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">AppHttpMiddleware</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Closure</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">EnsureTokenIsValid</span> <span class="token punctuation">{</span> <span class="token comment">/** * Handle an incoming request. * * @param IlluminateHttpRequest $request * @param Closure $next * @return mixed */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Closure</span> <span class="token variable">$next</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Log the request and response details</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Request: '</span> <span class="token operator">.</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">url</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Log</span><span class="token operator">::</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Response: '</span> <span class="token operator">.</span> <span class="token variable">$response</span><span class="token operator">-></span><span class="token function">status</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token variable">$response</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
Ở ví dụ này Middleware đã log lại lại các request url và response status sau khi request được xử lý
2.Đăng ký Middleware
2.1 Global Middleware
Khi bạn muốn tất cả các request đều phải đi qua 1 middleware nào đó thì bạn có thể thêm nó vào mảng $middleware trong app/Http/Kernel.php
class:
2.2 Áp dụng Middleware cho route
Để áp dụng middleware cho 1 route cụ thể nào đó, bạn chỉ cần gọi đến method middleware khi khai báo route:
1 2 3 4 5 6 | <span class="token keyword">use</span> <span class="token package">AppHttpMiddlewareAuthenticate</span><span class="token punctuation">;</span> <span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/profile'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token class-name static-context">Authenticate</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Hoặc bạn có thể áp dụng nhiều middleware cho cùng 1 route như sau:
1 2 3 4 | <span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token class-name static-context">First</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name static-context">Second</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token operator">**</span><span class="token operator">**</span> |
Để ngắn gọn hơn bạn có thể đặt tên cho middleware của bạn và sử dụng tên đó khi khai báo route. Việc đặt tên đó được viết trong app/Http/Kernel.php
với $middlewareAliases property:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token comment">// Within AppHttpKernel class...</span> <span class="token keyword">protected</span> <span class="token variable">$middlewareAliases</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token string single-quoted-string">'auth'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">AppHttpMiddlewareAuthenticate</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'auth.basic'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">IlluminateAuthMiddlewareAuthenticateWithBasicAuth</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'bindings'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">IlluminateRoutingMiddlewareSubstituteBindings</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'cache.headers'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">IlluminateHttpMiddlewareSetCacheHeaders</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'can'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">IlluminateAuthMiddlewareAuthorize</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'guest'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">AppHttpMiddlewareRedirectIfAuthenticated</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'signed'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">IlluminateRoutingMiddlewareValidateSignature</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'throttle'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">IlluminateRoutingMiddlewareThrottleRequests</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'verified'</span> <span class="token operator">=></span> <span class="token class-name class-name-fully-qualified static-context">IlluminateAuthMiddlewareEnsureEmailIsVerified</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> |
Sau đó bạn có thể sử dụng nó như sau:
1 2 3 4 | <span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/profile'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
2.3 Áp dụng Middleware cho group route
Khi bạn muốn áp dụng middleware cho nhiều route bạn có thể gộp các route đó thành group và áp dụng middleware cho group đó. Bạn cũng có thể áp dụng được nhiều middleware cho 1 group:
1 2 3 4 | <span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'verified'</span><span class="token punctuation">,</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">group</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Có trường hợp bạn sử dụng middleware cho 1 nhóm route nào đó nhưng có 1 route bạn không muốn áp dụng middleware đó bạn có thể sử dụng tới method withoutMiddleware:
1 2 3 4 5 6 7 8 9 10 | <span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'verified'</span><span class="token punctuation">,</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">group</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/profile'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">withoutMiddleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'verified'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Bạn cũng có thể sử dụng withoutMiddleware cho group route
withoutMiddleware chỉ áp dụng được với route middleware, không áp dụng được cho global middleware
2.4 Sắp xếp Middleware
Thông thường middleware sẽ được thực thi theo thứ tự từ trên xuống. Nhưng nếu bạn muốn thay đổi thứ tự ưu tiên của một middleware nào đó. Bạn có thể thêm vào trong thuộc tính $middlewarePriority trong file app/Http/Kernel.php
.
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">protected</span> <span class="token variable">$middlewarePriority</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token class-name class-name-fully-qualified static-context">IlluminateCookieMiddlewareEncryptCookies</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context">IlluminateSessionMiddlewareStartSession</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context">IlluminateViewMiddlewareShareErrorsFromSession</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context">IlluminateContractsAuthMiddlewareAuthenticatesRequests</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context">IlluminateRoutingMiddlewareThrottleRequests</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context">IlluminateSessionMiddlewareAuthenticateSession</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context">IlluminateRoutingMiddlewareSubstituteBindings</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name class-name-fully-qualified static-context">IlluminateAuthMiddlewareAuthorize</span><span class="token operator">::</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> |
3. Middleware Parameters
Middleware cũng có thể nhận được tham số truyền vào. Ví dụ với trường hợp: ứng dụng của bạn cần xác định role của người dùng là gì trước khi thực thi . Ví dụ với EnsureUserHasRole middleware dưới đây:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">AppHttpMiddleware</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Closure</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">IlluminateHttpRequest</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">SymfonyComponentHttpFoundationResponse</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name-definition class-name">EnsureUserHasRole</span> <span class="token punctuation">{</span> <span class="token comment">/** * Handle an incoming request. * * @param Closure(IlluminateHttpRequest): (SymfonyComponentHttpFoundationResponse) $next */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">,</span> <span class="token class-name type-declaration">Closure</span> <span class="token variable">$next</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$role</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name return-type">Response</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span> <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">hasRole</span><span class="token punctuation">(</span><span class="token variable">$role</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Redirect...</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token variable">$next</span><span class="token punctuation">(</span><span class="token variable">$request</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
Và khi khai báo route để truyền tham số vào cho middleware bạn sử dụng dấu : nếu có nhiều tham số thì ngăn cách nhau bằng dấu phẩy:
1 2 3 | <span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/post/{id}'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token keyword type-hint">string</span> <span class="token variable">$id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// ...</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'role:editor'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |