我已经使用 Laravel Passport 实现了一个 OAuth 系统,但是该系统的登录和所有身份验证均由具有 Inertia 的 Laravel Jetstream 处理。
当我想要请求代码(使用授权代码授予)时,我的应用程序将我重定向到我的 OAuth 服务器,该服务器在继续之前要求我登录,此屏幕是使用 Inertia (Vue) 登录 Laravel Jetstream 生成的屏幕。当我登录时,它会将我重定向到授权页面,但是这个重定向很奇怪,因为该页面显示在 Vue(惯性)页面内,浏览器中的 URL 不会更新,并且如果我接受授权请求它将我重定向回我的应用程序,但重定向位于同一个 Vue 页面内,我的意思是,URL 与我的 OAuth 服务器登录名相同,但视图是请求代码的我的应用程序。
我认为 Vue 中的重定向存在问题,因为授权页面没有使用 Inertia(Laravel Passport 的默认授权页面),我不知道如何修复它,你能帮我吗?
这是一张图片:
正如你所看到的,它似乎是在模态中,但是是一个惯性错误页面,并且里面显示的是授权页面,是一个重定向错误,我不知道如何修复
我和你有同样的问题 我解决如下:
在文件中
AuthenticatedSessionController.php
/**
* Handle an incoming authentication request.
*
* @param \App\Http\Requests\Auth\LoginRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(LoginRequest $request)
{
$request->authenticate();
$request->session()->regenerate();
if ($request->session()->has('url.intended')) {
return Inertia::location(session('url.intended'));
}
return redirect()->intended(RouteServiceProvider::HOME);
}
我知道这是一个老问题 - 但我今天自己偶然发现了这个问题,发现这里有人问这个问题 - 它给了我一些如何解决它的信息 - 但在检查代码后,Laravel Jetstream/Fortify 中的一些事情似乎发生了变化下面的解决方案现在似乎更准确,更容易实现,因为提到的
AuthenticatedSessionController.php
位于包内,并且下面可以在用户代码中完成,而无需接触包代码本身。
我通过覆盖 Laravel Fortify 内部使用的
*Reponse
类来解决这个问题,下面是我在代码中的两个覆盖:
正常登录流程需要
LoginResponse
:
<?php
namespace App\Http\Responses;
use Inertia\Inertia;
use Laravel\Fortify\Http\Responses\LoginResponse as LoginResponseBase;
class LoginResponse extends LoginResponseBase
{
/**
* Create an HTTP response that represents the object.
*
* @param \Illuminate\Http\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function toResponse($request)
{
if ($request->session()->has('url.intended')) {
return Inertia::location(session('url.intended'));
}
return parent::toResponse($request);
}
}
添加
App\Providers\FortifyServiceProvider::register
以下行来覆盖它(不要忘记 use 语句):
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
use App\Http\Responses\LoginResponse;
...
public function register()
{
...
$this->app->singleton(LoginResponseContract::class, LoginResponse::class);
...
}
使用 2FA 时需要
TwoFactorLoginResponse
,否则这也会像正常登录一样中断:
<?php
namespace App\Http\Responses;
use Inertia\Inertia;
use Laravel\Fortify\Http\Responses\TwoFactorLoginResponse as TwoFactorLoginResponseBase;
class TwoFactorLoginResponse extends TwoFactorLoginResponseBase
{
/**
* Create an HTTP response that represents the object.
*
* @param \Illuminate\Http\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function toResponse($request)
{
if ($request->session()->has('url.intended')) {
return Inertia::location(session('url.intended'));
}
return parent::toResponse($request);
}
}
添加
App\Providers\FortifyServiceProvider::register
以下行来覆盖它(不要忘记 use 语句):
use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract;
use App\Http\Responses\TwoFactorLoginResponse;
...
public function register()
{
...
$this->app->singleton(TwoFactorLoginResponseContract::class, TwoFactorLoginResponse::class);
...
}
上述更改只是确保给出正确的响应,以便 Inertia 根据其文档正确处理重定向: https://inertiajs.com/redirects#external-redirects
如果请求来自 Inertia,您必须更改登录操作的默认视图。您可以在 FortifyServiceProvider 中完成。
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\ServiceProvider;
use Inertia\Inertia;
use Laravel\Fortify\Fortify;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Fortify::loginView(function () {
if (Request::inertia()) {
return Inertia::location(url()->current());
}
return view('auth.login');
});
}
}
因为你使用的是惯性页面,所以不用 laravel 的重定向语法:
redirect($somewhere);
使用
use Inertia\Inertia;
// .... skip
Inertia::location($somewhere);
相反。
分享我的解决方案,使用自定义身份验证: 网页.php
Route::get('/login', [LoginController::class, 'wechatLogin'])->name('login');
Route::post('/login', [LoginController::class, 'authenticate']);
Route::post('/logout', [LoginController::class, 'logout'])->name('logout');
LoingController.php
...
public function authenticate(Request $request): RedirectResponse
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
return redirect(route('dashboard'));
}
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
])->onlyInput('email');
}
public function logout(Request $request)
{
Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return Inertia::location('/');
}
...