Laravel的租赁 - 从中​​央域发送的验证链接

发布于 2025-01-23 09:11:43 字数 3306 浏览 0 评论 0原文

我正在使用 laravel的租赁,然后遵循其文档的安装和Quickstart。除了验证链接外,一切都很好:

这个想法是在我的中央应用程序上注册,而我的租户上发生的一切都会发生。注册工作正常(在租户数据库上创建租户,域和用户),登录在租户方面正常工作,因此密码验证和密码恢复/重置也是如此。唯一无法正常工作的是电子邮件验证(每次用户注册时,系统都会发送电子邮件,该链接指向中央域而不是租户。)但是,如果用户点击“重新启动”,则会从租户域发送它这次。这是我的代码:

注册tenantController

class RegisteredTenantController extends Controller 
{
    public function create()
    {
        return view('auth.register');
    }

    public function store(RegisterTenantRequest $request)
    {
        $tenant = Tenant::create($request->validated());
        $tenant->createDomain(['domain' => $request->domain]);

        return redirect(tenant_route($tenant->domains->first()->domain, 'tenant.login'));
    }
}

tenancyserviceprovider

class TenancyServiceProvider extends ServiceProvider
{
    (...)
    
    public function events()
    {
        return [
            (...)
            Events\TenantCreated::class => [
                JobPipeline::make([
                    Jobs\CreateDatabase::class,
                    Jobs\MigrateDatabase::class,
                    CreateTenantAdmin::class,
                ])->send(function (Events\TenantCreated $event) {
                    return $event->tenant;
                })->shouldBeQueued(false), // `false` by default, but you probably want to make this `true` for production.
            ],
            (...)
        ];
    }

    (...)
}

createtenantadmin

class CreateTenantAdmin implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;


    public function __construct(public Tenant $tenant)
    {
        //
    }

    public function handle()
    {
        $this->tenant->run(function($tenant) {
            $user = User::create([
                'name' => $tenant->name,
                'email' => $tenant->email,
                'password' => $tenant->password,
            ]);

            $user->sendEmailVerificationNotification();
        });
    }
}

用户

class User extends Authenticatable implements MustVerifyEmail
{
    use HasApiTokens, HasFactory, Notifiable;

    (...)

    public function sendEmailVerificationNotification()
    {
        $this->notify(new CustomVerifyEmail);
    }
}

codusterifyemail

class CustomVerifyEmail extends VerifyEmail
{
    protected function verificationUrl($notifiable)
    {
        if (static::$createUrlCallback) {
            return call_user_func(static::$createUrlCallback, $notifiable);
        }

        return URL::temporarySignedRoute('tenant.verification.verify',
            Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
            [
                'id' => $notifiable->getKey(),
                'hash' => sha1($notifiable->getEmailForVerification()),
            ]
        );
    }
}

我所有的路由都配置为具有“租户”。如果要在租户应用程序上送达他们的名字。 (例如tenant.verification.verify哪个有效但我必须输入它)

我最好的猜测是url :: extureSignedRoute正在抓住该特定时刻在该页面上访问该页面的任何域,并且由于登记处发生在我的中心应用程序上,这会解释为什么会解释为什么会解释为什么“第一个”电子邮件具有中央域,但每个“重试”都带有租户域。

有人可以使用这个包装吗?

i'm using Tenancy For Laravel and followed the installation and quickstart from their documentation. Everything is working fine except the verification link:

The idea is register on my central app and everything else happening on my tenants. Register is working fine (creates a tenant, a domain and a user on the tenant database), login is working fine on the tenant side, so is password verification and password recovery/reset. The only thing not working fine is the email verification (Everytime a user register the system send the email with the link pointing to the central domain instead of the tenant one.) But if the user taps "resend" it sends it from the tenant domain this time. This is my code:

RegisteredTenantController

class RegisteredTenantController extends Controller 
{
    public function create()
    {
        return view('auth.register');
    }

    public function store(RegisterTenantRequest $request)
    {
        $tenant = Tenant::create($request->validated());
        $tenant->createDomain(['domain' => $request->domain]);

        return redirect(tenant_route($tenant->domains->first()->domain, 'tenant.login'));
    }
}

TenancyServiceProvider

class TenancyServiceProvider extends ServiceProvider
{
    (...)
    
    public function events()
    {
        return [
            (...)
            Events\TenantCreated::class => [
                JobPipeline::make([
                    Jobs\CreateDatabase::class,
                    Jobs\MigrateDatabase::class,
                    CreateTenantAdmin::class,
                ])->send(function (Events\TenantCreated $event) {
                    return $event->tenant;
                })->shouldBeQueued(false), // `false` by default, but you probably want to make this `true` for production.
            ],
            (...)
        ];
    }

    (...)
}

CreateTenantAdmin

class CreateTenantAdmin implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;


    public function __construct(public Tenant $tenant)
    {
        //
    }

    public function handle()
    {
        $this->tenant->run(function($tenant) {
            $user = User::create([
                'name' => $tenant->name,
                'email' => $tenant->email,
                'password' => $tenant->password,
            ]);

            $user->sendEmailVerificationNotification();
        });
    }
}

User

class User extends Authenticatable implements MustVerifyEmail
{
    use HasApiTokens, HasFactory, Notifiable;

    (...)

    public function sendEmailVerificationNotification()
    {
        $this->notify(new CustomVerifyEmail);
    }
}

CustomVerifyEmail

class CustomVerifyEmail extends VerifyEmail
{
    protected function verificationUrl($notifiable)
    {
        if (static::$createUrlCallback) {
            return call_user_func(static::$createUrlCallback, $notifiable);
        }

        return URL::temporarySignedRoute('tenant.verification.verify',
            Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
            [
                'id' => $notifiable->getKey(),
                'hash' => sha1($notifiable->getEmailForVerification()),
            ]
        );
    }
}

All my routes are configured to have "tenant." prefixed to their names if they are to be served on the tenant app. (like tenant.verification.verify which works but i have to type it in)

My best guess is URL::temporarySignedRoute is grabbing whichever domain is accessing the page at that particular moment and since register happens on my central app that would explain why the "first" email has the central domain but every "retry" comes with the tenant domain.

Anyone has got this to work with this package?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

薆情海 2025-01-30 09:11:43

这就是我最终要做的:

将其添加到照明\ routing \ urlGenerator

public function temporaryTenantSignedRoute($name, $expiration, $parameters = [], $absolute = true)
{
    return $this->tenantSignedRoute($name, $parameters, $expiration, $absolute);
}

public function tenantSignedRoute($name, $parameters = [], $expiration = null, $absolute = true)
{
    $this->ensureSignedRouteParametersAreNotReserved(
        $parameters = Arr::wrap($parameters)
    );

    if ($expiration) {
        $parameters = $parameters + ['expires' => $this->availableAt($expiration)];
    }

    ksort($parameters);

    $key = call_user_func($this->keyResolver);

    return tenant_route(tenant()->domains->first()->domain, $name, $parameters + [
        'signature' => hash_hmac('sha256', tenant_route(tenant()->domains->first()->domain, $name, $parameters, $absolute), $key),
    ], $absolute);
}

将其添加到custerverifyemail在ChastverifyEmail中,将其添加到Illuminate \ support \ support \ url

@method static string temporaryTenantSignedRoute(string $name, \DateTimeInterface|\DateInterval|int $expiration, array $parameters = [], bool $absolute = true)

更改此

Url::temporarySignedRoute

Url::temporaryTenantSignedRoute

This is what i ended up doing:

Add this to Illuminate\Routing\UrlGenerator

public function temporaryTenantSignedRoute($name, $expiration, $parameters = [], $absolute = true)
{
    return $this->tenantSignedRoute($name, $parameters, $expiration, $absolute);
}

public function tenantSignedRoute($name, $parameters = [], $expiration = null, $absolute = true)
{
    $this->ensureSignedRouteParametersAreNotReserved(
        $parameters = Arr::wrap($parameters)
    );

    if ($expiration) {
        $parameters = $parameters + ['expires' => $this->availableAt($expiration)];
    }

    ksort($parameters);

    $key = call_user_func($this->keyResolver);

    return tenant_route(tenant()->domains->first()->domain, $name, $parameters + [
        'signature' => hash_hmac('sha256', tenant_route(tenant()->domains->first()->domain, $name, $parameters, $absolute), $key),
    ], $absolute);
}

Add this to Illuminate\Support\Facades\URL

@method static string temporaryTenantSignedRoute(string $name, \DateTimeInterface|\DateInterval|int $expiration, array $parameters = [], bool $absolute = true)

In CustomVerifyEmail change this

Url::temporarySignedRoute

to this

Url::temporaryTenantSignedRoute
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文