无全局作用域的Laravel身份验证
在my Laravel应用程序中,用户可以禁用(而不是删除)他们的帐户以从网站上消失。但是,如果他们再次尝试登录,他们的帐户应自动激活,并应成功登录 这是通过用户表中的“活动”列和用户模型中的全局范围完成的:无全局作用域的Laravel身份验证,laravel,authentication,Laravel,Authentication,在my Laravel应用程序中,用户可以禁用(而不是删除)他们的帐户以从网站上消失。但是,如果他们再次尝试登录,他们的帐户应自动激活,并应成功登录 这是通过用户表中的“活动”列和用户模型中的全局范围完成的: protected static function boot() { parent::boot(); static::addGlobalScope('active', function(Builder $builder) { $builder->wh
protected static function boot() {
parent::boot();
static::addGlobalScope('active', function(Builder $builder) {
$builder->where('active', 1);
});
}
现在的问题是,这些非活动帐户无法再次登录,因为AuthController找不到它们(超出范围)
我需要达到的目标是:
$user = User::withoutGlobalScope('active')
->where('username', $request->username)
->first();
if($user != null) {
if (Hash::check($request->username, $user->password))
{
// Set active column to 1
}
}
return $this->login($request);
所以问题是如何让AuthController忽略全局作用域而不改变Laravel主代码,这样它将保留更新
谢谢。创建一个类
GlobalUserProvider
,该类扩展了EloquentUserProvider
,如下所示
class GlobalUserProvider extends EloquentUserProvider {
public function createModel() {
$model = parent::createModel();
return $model->withoutGlobalScope('active');
}
}
在AuthServiceProvider
中注册您的新用户提供程序:
Auth::provider('globalUserProvider', function ($app, array $config) {
return new GlobalUserProvider($this->app->make('hash'), $config['model']);
});
最后,您应该在auth.php
config文件中将用户提供程序驱动程序更改为globalUserProvider
'providers' => [
'users' => [
'driver' => 'globalUserProvider',
'model' => App\Models\User::class
]
]
请尝试此登录问题,您可以在登录后使用
而不使用GlobalScopes()
使用您在OP中使用的代码扩展AuthController
。这应该可以工作
public function postLogin(Request $request)
{
$user = User::withoutGlobalScope('active')
->where('username', $request->username)
->first();
if($user != null){
if (Hash::check($request->password, $user->password)){
$user->active = 1;
$user->save();
}
}
return $this->login($request);
}
@Sasan的答案在Laravel 5.3中运行良好,但在5.4中不起作用-createModel()需要一个
Model
,但得到一个Builder
对象,因此当EloquentUserProvider
调用$Model->getAuthIdentifierName()
时会引发异常:
BadMethodCallException: Call to undefined method Illuminate\Database\Query\Builder::getAuthIdentifierName() in /var/www/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:2445
相反,请遵循相同的方法,但覆盖更多函数,以便从createModel()
返回正确的对象
getQuery()
返回没有全局作用域的生成器,其他两个函数使用全局作用域
class GlobalUserProvider extends EloquentUserProvider
{
/**
* Get query builder for the model
*
* @return \Illuminate\Database\Eloquent\Builder
*/
private function getQuery()
{
$model = $this->createModel();
return $model->withoutGlobalScope('active');
}
/**
* Retrieve a user by their unique identifier.
*
* @param mixed $identifier
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier)
{
$model = $this->createModel();
return $this->getQuery()
->where($model->getAuthIdentifierName(), $identifier)
->first();
}
/**
* Retrieve a user by their unique identifier and "remember me" token.
*
* @param mixed $identifier
* @param string $token
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByToken($identifier, $token)
{
$model = $this->createModel();
return $this->getQuery()
->where($model->getAuthIdentifierName(), $identifier)
->where($model->getRememberTokenName(), $token)
->first();
}
}
我通过创建新包解决了这个问题 运行
composer require-mpyw/scoped-auth
并修改您的用户模型,如下所示:
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Mpyw\ScopedAuth\AuthScopable;
class User extends Model implements UserContract, AuthScopable
{
use Authenticatable;
public function scopeForAuthentication(Builder $query): Builder
{
return $query->withoutGlobalScope('active');
}
}
萨桑·法罗克有一个正确的答案。唯一不重写createModel而重写newModelQuery的方法就是这样做
protected function newModelQuery($model = null)
{
$modelQuery = parent::newModelQuery();
return $modelQuery->withoutGlobalScope('active');
}
我不得不使用
->不使用GlobalScopes()
为了让它工作我遇到了类似的问题。我使用了这个解决方案:创建两个独立的用户模型。第一个没有全局作用域,仅用于身份验证。第二个扩展了第一个,包括全局范围,并用于其他所有内容。如果我错了,请纠正我,但您在这里没有使用不带全局范围的
回答您自己的问题吗?请参阅链接:这不起作用<代码>$model->without globalscope('active')代码>失败,因为父级::createModel()代码>返回一个用户对象<但是,必须在查询中调用code>Without GlobalScope
。对我来说非常有效-帮助避免了Symfony\Component\Debug\Exception\FatalThrowable错误:已达到最大函数嵌套级别“256”,正在中止代码>全局作用域应用于用户模型时出错,该模型正在检查用户是否经过身份验证(从而再次引导用户)。对,您必须重写此函数,而不是newModelQuery()。这对以后版本的Laravel有效吗?我试图在文档中找到“postLogin”,但找不到。此外,AuthController现在似乎是LoginController和RegisterController。这里的问题是在auth
中间件中,它将看不到任何auth用户,因此您将被记录out@TheGeeky我没有在这里使用auth中间件任何其他路由,“<代码> Auth<代码>中间件将使用您所做的范围,并考虑您的访客用户名不是真的-我正在设置$USER -> Active=1,这样,下一次他们提出请求时,它就认为是一个活动用户,并将与AuthMealDeWorksAudio.<代码> Auth中间件将自动注销用户,因此这是一个坏的解决方案。
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
\Illuminate\Auth\Events\Login::class => [
\App\Listeners\ActivateUser::class,
],
];
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
parent::boot();
//
}
}
<?php
namespace App\Listeners;
use Illuminate\Auth\Events\Login;
class ActivateUser
{
/**
* Handle the event.
*
* @param Illuminate\Auth\Events\Login $event
* @return void
*/
public function handle(Login $event)
{
$event->user->fill('active', 1)->save();
}
}
protected function newModelQuery($model = null)
{
$modelQuery = parent::newModelQuery();
return $modelQuery->withoutGlobalScope('active');
}