Задать вопрос
@Sasha_212

Laravel+Vue Как сделать капчу?

у меня есть шаблон app.vue с формой для написания комментария:
<template>
    <div class="container mt-5">
        <div class="card shadow">
            <div class="card-header bg-primary text-white">
                <h3>Contact Form</h3>
            </div>
            <div class="card-body">
                <div v-if="replyingToComment" class="alert alert-secondary" role="alert">
                    Ответ на комментарий: "{{ replyingToComment.text.substring(0, 20) }}..."
                </div>
                <form @submit.prevent="submitForm">
                    <!-- Other form fields -->
                    <div class="mb-3">
                        <label for="username" class="form-label">UserName</label>
                        <input type="text" v-model="comment.username" id="username" class="form-control" placeholder="Enter your username" required />
                    </div>
                    <div class="mb-3">
                        <label for="email" class="form-label">E-mail</label>
                        <input type="email" v-model="comment.email" id="email" class="form-control" placeholder="Enter your email" required />
                    </div>
                    <div class="mb-3">
                        <label for="homepage" class="form-label">Home page</label>
                        <input type="url" v-model="comment.homepage" id="homepage" class="form-control" placeholder="Enter your homepage (optional)" />
                    </div>
                    <div class="mb-3">
                        <label for="text" class="form-label">Text</label>
                        <textarea v-model="comment.text" id="text" class="form-control" rows="5" placeholder="Enter your message" required></textarea>
                    </div>
                    <div class="mb-3">
                        <label for="file" class="form-label">File (Max 10MB)</label>
                        <input type="file" ref="file" id="file" class="form-control" />
                    </div>

                    <!-- CAPTCHA -->
                    <div class="mb-3">
                        <label for="captcha" class="form-label">Captcha</label>
                        <img :src="captchaImage" alt="CAPTCHA Image" class="mb-2" @click="loadCaptcha" style="cursor: pointer;" />
                        <input type="text" v-model="captcha" id="captcha" class="form-control" placeholder="Enter CAPTCHA" required />
                        <input type="hidden" v-model="captchaKey" id="captchaKey" name="key" />
                    </div>

                    <!-- Error message display -->
                    <div v-if="errorMessage" class="alert alert-danger">
                        {{ errorMessage }}
                    </div>

                    <button type="submit" class="btn btn-primary">Submit</button>
                </form>
            </div>
        </div>
    </div>
    <div id="app">
        <Comments @setParentId="setParentId" />
    </div>
</template>

<script>
import axios from 'axios';
import Comments from '../components/Comments.vue';

export default {
    name: 'App',
    components: {
        Comments,
    },
    data() {
        return {
            comment: {
                username: '',
                email: '',
                homepage: '',
                text: '',
                parent_id: null
            },
            captcha: '',
            captchaKey: '',
            captchaImage: '',
            errorMessage: '',
            replyingToComment: null,
        }
    },
    computed: {
        isNewComment() {
            return !this.$route.path.includes('edit');
        }
    },
    async created() {
        await this.loadCaptcha();
        if (!this.isNewComment) {
            const response = await axios.get(`/api/comments/${this.$route.params.id}`);
            this.comment = response.data;
        }
    },
    methods: {
        async loadCaptcha() {
            try {
                const response = await axios.get('/captcha/api/math');
                this.captchaImage = response.data.img;
                this.captchaKey = response.data.key; // Assuming the response includes the key
            } catch (error) {
                console.error('Error loading CAPTCHA:', error);
            }
        },
        async submitForm() {
            try {
                const formData = new FormData();
                formData.append('username', this.comment.username);
                formData.append('email', this.comment.email);
                formData.append('homepage', this.comment.homepage);
                formData.append('text', this.comment.text);
                formData.append('parent_id', this.comment.parent_id);
                formData.append('captcha', this.captcha);
                formData.append('key', this.captchaKey); // Pass the CAPTCHA key
                if (this.$refs.file.files[0]) {
                    formData.append('file', this.$refs.file.files[0]);
                }

                console.log(formData);

                const response = await axios.post('/api/comments/validate', formData);
                this.$router.push('/');
            } catch (error) {
                if (error.response && error.response.data.errors) {
                    this.errorMessage = Object.values(error.response.data.errors).flat().join('\n');
                } else {
                    console.error(error);
                }
            }
        },
        async setParentId(parentId) {
            this.comment.parent_id = parentId;

            try {
                const response = await axios.get(`/api/comments/${parentId}`);
                this.replyingToComment = response.data;
            } catch (error) {
                console.error('Error fetching parent comment:', error);
            }

            window.scrollTo(0, 0);
        }
    }
};
</script>


При отправке формы отправляется запрос на бекенд ларавеля, а именно в валидатор CommentController:
public function validateComment(Request $request)
    {

        $rules = [
            'captcha' => 'required|captcha_api:' . request('key') . ',math',
            'username' => 'required|string',
            'email' => 'required|email',
            'homepage' => 'nullable|url',
            'text' => 'required|string',
            'file' => 'nullable|file|max:10240', // 10MB max size
        ];

        $validator = validator()->make(request()->all(), $rules);


        if ($validator->fails()) {
            return response()->json(['errors' => $validator->errors()], 422);
        }

        else {
            return $this->storeComment($request);
        }

    }


Но почему-то при отправке формы с правильно введенной капчей мне прилетает ошибка
`POST localhost:9000/api/comments/validate 422 (Unprocessable Content)`
и в alert alert-danger пишет `validation.captcha_api`. В чем проблема? Я же вроде сделал все как в документации https://github.com/mewebstudio/captcha пишет. И нет, я не хочу использовать reCaptcha, только капчу где нужно вводить то, что на картинке, либо капчи с математической задачей, а на данный момент я нашел только mewebstudio/captcha
  • Вопрос задан
  • 437 просмотров
Подписаться 2 Простой 2 комментария
Решения вопроса 1
@Sasha_212 Автор вопроса
И так, я понял в чем дело... А дело в абсолютной корявости vue.js. Проблема в том, что когда vue.js отправляет данные на бекенд - он конвертирует числа в строки, то есть решение капчи, например число 21 превращается в беке в "21" и валидатор говорит, что решение неправильное. Я перед валидатором поставил такой код:
$request->captcha = intval($request->captcha);
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы