Как проверить электронную почту, не прося пользователя войти в Laravel

Я разрабатываю приложение Laravel. Мое приложение использует встроенную функцию аутентификации Laravel. В аутентификации Laravel при регистрации пользователя отправляется письмо с подтверждением. Когда пользователь проверяет адрес электронной почты, щелкнув ссылку внутри сообщения электронной почты, пользователь должен снова войти в систему, чтобы подтвердить адрес электронной почты, если пользователь еще не вошел в систему.

VerificationController

class VerificationController extends Controller
{
    use VerifiesEmails, RedirectsUsersBasedOnRoles;

    /**
     * Create a new controller instance.
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('signed')->only('verify');
        $this->middleware('throttle:6,1')->only('verify', 'resend');
    }

    public function redirectPath()
    {
        return $this->getRedirectTo(Auth::guard()->user());
    }
}

Я пробовал комментировать эту строчку.

$this->middleware('auth');

Но это не работает, а вместо этого выдает ошибку. Как я могу включить Laravel, чтобы иметь возможность проверять электронную почту, даже если пользователь не вошел в систему?

Почему вы хотите этого? Теперь я могу просто передать это электронное письмо и захватить любую учетную запись.

Loek 21.12.2018 14:18

Что делает RedirectsUsersBasedOnRoles? Когда вы говорите «Это не работает», что вы имеете в виду; вы получаете ошибку? Что за ошибка?

Zoe Edwards 21.12.2018 14:20

Он выдает ошибку, потому что ожидает экземпляр вашего пользователя. См .: github.com/laravel/framework/blob/…

adam 21.12.2018 16:58

Спасибо, Адам. Спасибо, Лук, что указал на разумную причину. Ваше здоровье

Wai Yan Hein 21.12.2018 17:20

как так @Loek? URL подписан.

AaronHS 15.08.2019 09:12
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Laravel Scout - это популярный пакет, который предоставляет простой и удобный способ добавить полнотекстовый поиск в ваше приложение Laravel. Он...
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
22
5
18 736
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Сначала удалите строку $this->middleware('auth');, как вы это сделали.

Затем скопируйте метод verify из свойства VerifiesEmails на свой VerificationController и немного измените его. Метод должен выглядеть так:

public function verify(Request $request)
{
    $user = User::find($request->route('id'));

    if (!hash_equals((string) $request->route('hash'), sha1($user->getEmailForVerification()))) {
        throw new AuthorizationException;
    }

    if ($user->markEmailAsVerified())
        event(new Verified($user));

    return redirect($this->redirectPath())->with('verified', true);
}

Это отменяет метод в трейте VerifiesUsers и удаляет проверку авторизации.

Безопасность (поправьте меня, если я ошибаюсь!)

Это по-прежнему безопасно, так как запрос подписан и проверен. Кто-то может проверить адрес электронной почты другого пользователя, если он каким-то образом получит доступ к проверочному электронному письму, но в 99% случаев это вряд ли вообще представляет собой риск.

Могу ли я использовать этот метод, не беспокоясь о проблемах безопасности?

Ishaan 08.08.2019 20:25

Это было отредактировано для Laravel 6? В предыдущих версиях ваше индивидуальное сравнение хешей не было обязательным, верно?

Traxo 23.02.2020 11:29

Вызов неопределенного метода App \ User :: getEmailForVerification ()

Sead Lab 12.05.2020 12:26

@SeadLab убедитесь, что вы включили трейт MustVerifyEmail в модель User. Кроме этого, я не уверен, изменилось ли что-нибудь в Laravel 7.

Wouter Florijn 13.05.2020 10:58

если вы хотите активировать учетную запись пользователя без входа в систему, вы можете сделать это за 2 шага

1- Удалить или прокомментировать промежуточное ПО Auth в VerificationController

Пример ниже:

public function __construct()
{
    //$this->middleware('auth');
    $this->middleware('signed')->only('verify');
    $this->middleware('throttle:6,1')->only('verify', 'resend');
}

2- поскольку проверка маршрута проходит через {id}, вы можете просто отредактировать функцию проверки, чтобы найти пользователя по запросу идентификатора маршрута, как показано ниже:

путь к файлу: *: \ yourproject \ vendor \ laravel \ framework \ src \ Illuminate \ Foundation \ Auth \ VerifyEmails.php

$user = User::findOrfail($request->route('id'));

Полный пример

public function verify(Request $request)
{
    $user = User::findOrfail($request->route('id'));

    if (! hash_equals((string) $request->route('id'), (string) $user->getKey())) {
        throw new AuthorizationException;
    }

    if (! hash_equals((string) $request->route('hash'), sha1($user->getEmailForVerification()))) {
        throw new AuthorizationException;
    }

    if ($user->hasVerifiedEmail()) {
        return redirect($this->redirectPath())->with('verified', true);
    }

    if ($user->markEmailAsVerified()) {
        event(new Verified($request->user()));
    }

    return redirect($this->redirectPath())->with('registered', true);
}

Привет, серфинг. Пожалуйста, подумайте о добавлении описания к вашему примеру кода.

Eyk Rehbein 04.01.2020 14:57
// For Laravel 6 and Above 
use Illuminate\Auth\Events\Verified; 
use Illuminate\Http\Request; 
use App\User;

// comment auth middleware
//$this->middleware('auth');

public function verify(Request $request)
{
    $user = User::find($request->route('id'));

    if (!hash_equals((string) $request->route('hash'), sha1($user->getEmailForVerification()))) {
        throw new AuthorizationException;
    }

    if ($user->markEmailAsVerified())
        event(new Verified($user));

    return redirect($this->redirectPath())->with('verified', true);
}

Бесполезно: точно такой же код, как в принятом ответе, и добавлен после последнего редактирования.

Jan Żankowski 27.05.2021 16:27

Вот более перспективное решение проблемы:

class VerificationController extends Controller
{

    // …

    use VerifiesEmails {
        verify as originalVerify;
    }

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth'); // DON'T REMOVE THIS
        $this->middleware('signed')->only('verify');
        $this->middleware('throttle:6,1')->only('verify', 'resend');
    }

    /**
     * Mark the authenticated user's email address as verified.
     *
     * @param Request $request
     * @return Response
     *
     * @throws AuthorizationException
     */
    public function verify(Request $request)
    {
        $request->setUserResolver(function () use ($request) {
            return User::findOrFail($request->route('id'));
        });
        return $this->originalVerify($request);
    }
}

Поэтому, когда неаутентифицированный пользователь нажимает ссылку для подтверждения по электронной почте, происходит следующее:

  1. Пользователь будет перенаправлен на страницу входа в систему 1.
  2. Пользователь вводит учетные данные; успешно входит в систему 2
  3. Пользователь будет перенаправлен обратно на URL-адрес подтверждения электронной почты
  4. Электронная почта будет отмечена как подтвержденная

1 На этом этапе электронное письмо не будет помечено как подтвержденное.

2 Пользователь может вводить неверные учетные данные несколько раз. Как только он введет правильные учетные данные, он будет перенаправлен на предполагаемый URL-адрес подтверждения электронной почты.

Однако трейт VerifyEmails был удален в Laravel 7.x.

Nina Lisitsinskaya 09.03.2021 03:11

Я получаю при этом «Сначала необходимо подтвердить свой адрес электронной почты».

Gaurav 12.03.2021 14:34

Не следует удалять $this->middleware('auth') полностью, так как это повлияет на перенаправления. Если вы удалите его, неаутентифицированные пользователи будут перенаправлены на «/ email / verify» вместо «/ login».

поэтому $this->middleware('auth'); будет заменен на $this->middleware('auth')->except('verify'); в "VerificationController"

Также скопируйте функцию «verify» из «VerifyEmails» в «VerificationController».

добавьте эти две строки кода вверху функции

$user = User::find($request->route('id'));

auth()->login($user);

поэтому вы программно входите в систему, а затем выполняете дальнейшие действия

Решение для разрешения проверки электронной почты для пользователей, которые не вошли в систему (т.е. без авторизации):

Изменения в: app / Http / Controllers / Auth / VerificationController.php:

  1. $this->middleware('auth'); в $this->middleware('auth')->except('verify');
  2. Скопируйте метод verify() из признака VerifiesEmails.
  3. Отредактируйте метод проверки, чтобы он работал без ожидаемых данных $request->user().

Мой метод verify() в VerificationController выглядит так:

public function verify(\Illuminate\Http\Request $request)
{
    $user = User::find($request->route('id'));

    if ($request->route('id') != $user->getKey()) {
        throw new AuthorizationException;
    }

    if ($user->markEmailAsVerified())
        event(new Verified($user));

    return redirect()->route('login')->with('verified', true);
}

Подписанное промежуточное ПО

Laravel использует промежуточное ПО с именем signed для проверки целостности URL-адресов, сгенерированных приложением. Подписано проверяет, был ли изменен URL-адрес с момента его создания. Попробуйте изменить идентификатор, время истечения срока действия или подпись в URL-адресе, и это приведет к ошибке - очень эффективное и полезное промежуточное ПО для защиты метода verify ()

Для получения дополнительной информации: https://laravel.com/docs/8.x/urls#signed-urls

(По желанию)

Я перенаправил своих пользователей на маршрут входа, а не на предполагаемый маршрут по двум причинам. 1) После входа в систему он пытался перенаправить пользователя на ссылку для подтверждения адреса электронной почты, что приводило к ошибке; 2) Я хотел использовать проверенные истинные флэш-данные, которые были прикреплены к перенаправлению, чтобы отображать предупреждение на странице входа в систему, если пользователь успешно подтвердил свой адрес электронной почты.

Пример моего предупреждения на странице входа:

@if (session()->has('verified'))
    <div class = "alert alert-success">Your email address has been successfully verified.</div>
@endif

Предложения

Если у вас есть предложения по улучшению этого кода, дайте мне знать. Я был бы счастлив отредактировать этот ответ.

Вот мой взгляд на ситуацию. Проверка требует, чтобы пользователь вошел в систему, прежде чем он сможет завершить проверку, поэтому мы можем переопределить функцию проверки и войти в систему, используя идентификатор, который мы получили в ссылке. Это безопасная причина, по которой функция проверки не вызывается, если Laravel не может проверить подпись из URL-адреса, поэтому, даже если кто-то изменит URL-адрес, он не сможет его обойти.

Перейдите в свой VerificationController и добавьте следующую функцию в конец файла.

public function verify(Request $request)
{
    if (!auth()->check()) {
        auth()->loginUsingId($request->route('id'));
    }

    if ($request->route('id') != $request->user()->getKey()) {
        throw new AuthorizationException;
    }

    if ($request->user()->hasVerifiedEmail()) {
        return redirect($this->redirectPath());
    }

    if ($request->user()->markEmailAsVerified()) {
        event(new Verified($request->user()));
    }

    return redirect($this->redirectPath())->with('verified', true);
}

Примечание

Убедитесь, что для параметра same_site в config / session.php установлено значение lax. Если для него установлено значение «строгий», сеанс не будет сохраняться, если вы были перенаправлены с другого сайта. Например, если вы щелкнете ссылку подтверждения из Gmail, ваш файл cookie сеанса не будет сохраняться, поэтому он не будет перенаправлять вас на панель управления, но установит поле «email_verified_at» в базе данных, помечая проверку как успешную. Пользователь не поймет, что произошло, потому что это перенаправит пользователя на страницу входа. Если вы установили для него значение «строгий», он будет работать, если вы скопируете ссылку для подтверждения прямо в адресную строку браузера, но не если пользователь щелкнет ссылку в веб-клиенте Gmail, поскольку он использует перенаправление для отслеживания ссылки.

хорошая попытка. работает как положено для меня. Благодарность

Mohammad H. 06.06.2021 11:01

Другие вопросы по теме