Trong hai bài viết trước, mình đã hướng dẫn các bạn cách Slack Command hoạt động và cách tạo một Slack Command. Tiếp tục chuỗi bài viết này, mình sẽ hướng dẫn cách tạo route trong Laravel để nhận yêu cầu và gửi phản hồi Slack command.
Mục đích của chuỗi bài này là hướng dẫn nhận lệnh và phản hồi Slack command nên mình sẽ không đi sâu vào phần hướng dẫn cơ bản của Laravel.
Các phần trước
1/ Slack command & Laravel phần 1: Tìm hiểu về workflow
2/ Slack command & Laravel phần 2: Tạo App Slack và Command
Tạo route cho Laravel nhận dữ liệu
- Đầu tiên chúng ta sẽ tạo 1 controller và route cho Laravel nhận dữ liệu. Ở bài trước mình đã đặt url là api/hello-khanh, nên giờ mình sẽ tạo HelloController và route tương ứng của nó ở api route

- Controller này của mình hiện tại sẽ chỉ cần 1 action duy nhất, ở đây mình sẽ sử dụng action là __invoke() với biến $request để nhận dữ liệu từ Slack

Cấu trúc dữ liệu từ Slack
- Dữ liệu từ Slack gửi đến sẽ bao gồm chữ ký ở header và nội dung lệnh ở body

- Phần request body sẽ bao gồm thông tin lệnh, nội dung kèm theo, thông tin kênh và người gửi tin, trong trường hợp này mình đã gõ lệnh /hello-khanh từ channel Social và không kèm nội dung lệnh

- Như ở bài 1 mình đã có nói đến, chúng ta sẽ dùng chữ ký để xác thực tính hợp lệ của dữ liệu nhận được
Cơ chế xác thực chữ ký (verify signature)
- Slack sẽ ký từng yêu cầu gửi đến bằng một chữ ký độc nhất, sử dụng khóa bí mật (signing secret) của ứng dụng bạn. Việc xác thực chữ ký này giúp đảm bảo rằng dữ liệu thực sự đến từ Slack và không bị giả mạo.
- Trong mỗi request, Slack sẽ đính kèm chữ ký số ở phần header với tên là
X-Slack-Signature. Chữ ký này được tạo bằng cách sử dụng:- Nội dung gốc của request body (raw body)
- Thuật toán HMAC-SHA256
- Khóa bí mật (signing secret) của ứng dụng bạn.
- Lưu ý: request body phải sử dụng raw data chứ không dùng data đã được parse trong request body, trường hợp này raw data của mình là
token=6ypJOKONYBDqQaV0zl0mmdrB&team_id=T0956ELD1EU&team_domain=nhatkhanhworkspace&channel_id=C0956ELK4DN&channel_name=social&user_id=U0956ELD1J4&user_name=nhatkhanhtv3011&command=%2Fhello-khanh&text=&api_app_id=A095G2Q4CMD&is_enterprise_install=false&response_url=https%3A%2F%2Fhooks.slack.com%2Fcommands%2FT0956ELD1EU%2F9282720857456%2FU66UlN0vfrvDS9oDGL0YTrN7&trigger_id=9282720864432.9176496443504.61a492f23fe5bcf91c1b5204b32bd8c8
- Ngoài nội dung chữ ký (
X-Slack-Signature), Slack còn cung cấp phiên bản chữ ký — thường bắt đầu bằng tiền tố nhưv0=. Phần tiền tố này chính là thành phần bắt buộc khi tạo và xác thực chữ ký. Ví dụ mẫu chữ ký trong trường hợp này là:
v0=6c7e4fea3a73bd63755d65d9dc923468185b4fdc848bcf97e0fa58af568d58c6
- Slack sẽ tạo chữ ký bằng cách mã hóa một chuỗi có định dạng như sau:
<phiên bản>:<thời gian request>:<request body>
- Sau đó, chuỗi này sẽ được mã hóa bằng thuật toán HMAC với SHA256 và khóa bí mật (signing secret) của bạn:
hash_hmac('sha256', $baseString, $signingSecret);
Cơ chế là như vậy, giờ chúng ta sẽ cùng nhau thực hiện kiểm tra chữ ký này trong Laravel để đảm bảo rằng request thực sự đến từ Slack.
Xác thực bằng Laravel
- Mình sẽ dùng middleware để xác thực request trước khi truyền vào HelloController để xử lý lệnh.
- Đầu tiên, mình tạo 1 hàm để tạo chữ ký từ các thành phần trong request của Slack, bao gồm phiên bản (version), thời gian gửi (request time) và dữ liệu của phần body (payload).

- Ở Laravel, mình sẽ dùng hàm getContent() của request để lấy raw data.

- Tiếp theo ta lấy x-slack-signature, x-slack-request-timestamps và phiên bản của chữ ký

- Cuối cùng, mình truyền tất cả vào hàm _createHash() để tạo chữ ký và so sánh với chữ ký gốc ban đầu

- Bên dưới là hình ảnh toàn bộ đoạn code ở middleware

Phản hồi Slack Command
- Sau khi đã xác thực xong thì ta đã biết được yêu cầu này chính xác, giờ thì chúng ta có thể yên tâm phản hồi Slack command rồi.
- Slack command yêu cầu phản hồi nhanh trong vòng 3 giây, nếu không thì hệ thống sẽ báo dispatch_failed. Để phản hồi sau 3 giây thì ta cần dùng response_url nằm trong body cùa Slack Command
- Để phản hồi nhanh, ta đơn giản chỉ cần return 1 mảng gồm text và nội dung, kèm theo response_type (ephemeral hoặc in_channel) để chọn kiểu phản hồi mong muốn, mặc định khi phản hồi Slack command thì hệ thống sẽ dùng ephemeral – chỉ người gõ lệnh thấy, nếu bạn muốn tất cả mọi người trong kênh đều thấy link thì cần phải sử dụng in_channel

Phản hồi Slack command cần thời xử lý dữ liệu
- Nếu cần thời gian để xử lý dữ liệu, bạn nên phản hồi nhanh trong vòng 3 giây, kiểu như “Yêu cầu của bạn đang được xử lý!” sau đó trong vòng 30 phút, chúng ta sẽ gửi thêm kết quả bằng tương tự như gửi tin nhắn tới Slack nhưng với url là response_url trong body của Slack Command.
- Để mô phỏng quá trình xử lý dữ liệu, mình sẽ tạo 1 job trong Laravel để hàng chờ xử lý, tránh kéo dài thời gian phản hồi.

- Tiếp theo ở HelloController, mình sẽ gọi job này trước khi phản hồi Slack command

- Sau khi thành công thì Slack sẽ hiển thị như ảnh, trong bài này mình chỉ sử dụng text để phản hồi, Slack còn cung cấp các định dạng khác để cho phản hồi đẹp hơn, các bạn có thể tham khảo thêm để sử dụng tùy theo mục đích.

Qua 3 bài của series này, mình đã cùng các bạn tìm hiểu workflow, tạo app, command Slack và xử lý phản hồi Slack command bằng Laravel.
Nếu bạn có góp ý hoặc câu hỏi nào, đừng ngần ngại để lại bình luận cho mình, ý kiến của các bạn là động lực để mình tiếp tục tìm hiểu và chia sẽ các nội dung có ích hơn trong tương lại.
Đọc thêm
1/ Verifying requests from Slack


Để lại một bình luận