有效的方法是注销,使用ctrl/cmd + R刷新页面,然后再次登录。页面刷新解决了我的问题,这让我相信我没有正确处理X-CSRF-TOKEN的刷新,或者可能忘记了Laravel使用的某些cookies(如这里所述)。
这是执行用户单击登录按钮后执行的登录表单代码片段。
login(){
// Copy the form data
const data = {...this.user};
// If remember is false, don't send the parameter to the server
if(data.remember === false){
delete data.remember;
}
this.authenticating = true;
this.authenticate(data)
.then( this.refreshTokens )
.catch( error => {
this.authenticating = false;
if(error.response && [422, 423].includes(error.response.status) ){
this.validationErrors = error.response.data.errors;
this.showErrorMessage(error.response.data.message);
}else{
this.showErrorMessage(error.message);
}
});
},
refreshTokens(){
return new Promise((resolve, reject) => {
axios.get('/refreshtokens')
.then( response => {
window.Laravel.csrfToken = response.data.csrfToken;
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = response.data.csrfToken;
this.authenticating = false;
this.$router.replace(this.$route.query.redirect || '/');
return resolve(response);
})
.catch( error => {
this.showErrorMessage(error.message);
reject(error);
});
});
},
authenticate()
方法是一个 Vuex 操作,它调用 Laravel 端的登录终点。
/refreshTokens 终点只是调用了这个 Laravel 控制器函数,该函数返回当前已登录用户的 CSRF 令牌:
public function getCsrfToken(){
return ['csrfToken' => csrf_token()];
}
在重新获取令牌后,用户将被重定向到主页(或其他页面,如果提供了)this.$router.replace(this.$route.query.redirect || '/');
并调用 api/user
函数来检查当前登录用户的数据。
还有其他措施我需要采取以使它起作用吗?
感谢您的帮助!
编辑:2017年11月07日
在所有有用的建议之后,我想添加一些信息。我正在使用 Passport 在 Laravel 上进行身份验证,并且已经安装了 CreateFreshApiToken 中间件。
我一直在查看我的应用程序设置的 cookie,特别是 laravel_token
,据说它保存了加密的 JWT,Passport 将使用它来验证来自 JavaScript 应用程序的 API 请求。当注销时,laravel_token cookie 将被删除。然后立即再次登录(使用 axios 发送 AJAX post 请求),没有设置新的 laravel_token
,因此无法验证用户。我知道 Laravel 不会在登录 POST 请求上设置 cookie,但是 GET 请求到 /refreshTokens(不受保护)之后直接设置 cookie。然而,这似乎并没有发生。
我尝试增加请求 /refreshTokens
和请求 /api/user
之间的延迟时间,以便给服务器一些时间来整理事情,但是没有成功。
为了完整起见,这是我的 Auth\LoginController,它正在处理服务器端的登录请求:
class LoginController extends Controller
{
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '/';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
// $this->middleware('guest')->except('logout');
}
/**
* Get the needed authorization credentials from the request.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
protected function credentials(\Illuminate\Http\Request $request)
{
//return $request->only($this->username(), 'password');
return ['email' => $request->{$this->username()}, 'password' => $request->password, 'active' => 1];
}
/**
* The user has been authenticated.
*
* @param \Illuminate\Http\Request $request
* @param mixed $user
* @return mixed
*/
protected function authenticated(\Illuminate\Http\Request $request, $user)
{
$user->last_login = \Carbon\Carbon::now();
$user->timestamps = false;
$user->save();
$user->timestamps = true;
return (new UserResource($user))->additional(
['permissions' => $user->getUIPermissions()]
);
}
/**
* Log the user out of the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function logout(\Illuminate\Http\Request $request)
{
$this->guard()->logout();
$request->session()->invalidate();
}
}
axios.post('/logout')
即可。 - Daniel Schreijlaravel_token
的cookie中,这是一个httpOnly cookie,因此在JS中无法访问。许多来源都说浏览器应该负责处理这个令牌,即使它是通过ajax响应返回的,但显然在这里并非如此... - Daniel Schreij