Why Laravel Auth::guard()->attempt() isn't working? - php

So basically I generate users data after a payment, which it is saved in a table I created, it has a username and a encrypted password with Hash::make() method.
What I wanna do is to login with that data stored in the DB, so I made a guard.
This is the auth.php file with guards:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'plataforma' => [
'driver' => 'session',
'provider' => 'usuario',
],
],
And these are the providers:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'usuario' => [
'driver' => 'eloquent',
'model' => App\Models\Usuario::class,
],
This is the model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Usuario extends Authenticatable
{
use HasFactory;
use Notifiable;
protected $guard = 'plataforma';
protected $fillable = [
'nombre_usuario', 'correo', 'clave',
];
protected $hidden = [
'clave', 'remember_token',
];
}
And finally the controller:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class PlataformaController extends Controller
{
public function login()
{
return view('web.plataforma-login');
}
public function autenticar(Request $request)
{
if (Auth::guard('plataforma')->attempt(['nombre_usuario' => $request->input('nombre_usuario'), 'clave' => $request->input('clave')])) {
return view('web.plataforma');
} else {
dd(Auth::guard('plataforma')->attempt(['nombre_usuario' => $request->input('nombre_usuario'), 'clave' => $request->input('clave')]));
}
}
public function dashboard()
{
return view('web.plataforma');
}
}
So basically the Auth::guard('plataforma')->attempt(...) returns false, I already checked that the values of $request->input(...) are correct, I checked that the encrypted password in the DB is the same as the password that the user enter with Hash::check(), so I don't know what is wrong and I'm so confused...
I spent a lot of time reading other questions with no solutions either, I would be glad if anyone can help me out.

After reading the API, I've come to the conclusion attempt() is not working to you because you're using a different password column name.
The following is the attempt function's code from the Illuminate\Auth\SessionGuard class:
/**
* Attempt to authenticate a user using the given credentials.
*
* #param array $credentials
* #param bool $remember
* #return bool
*/
public function attempt(array $credentials = [], $remember = false)
{
$this->fireAttemptEvent($credentials, $remember);
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
// If an implementation of UserInterface was returned, we'll ask the provider
// to validate the user against the given credentials, and if they are in
// fact valid we'll log the users into the application and return true.
if ($this->hasValidCredentials($user, $credentials)) {
$this->login($user, $remember);
return true;
}
// If the authentication attempt fails we will fire an event so that the user
// may be notified of any suspicious attempts to access their account from
// an unrecognized user. A developer may listen to this event as needed.
$this->fireFailedEvent($user, $credentials);
return false;
}
The key functions here are retrieveByCredentials and hasValidCredentials
Here's retrieveByCredentials from Illuminate\Auth\EloquentUserProvider. As you can see, it's excluding the 'password' key from the query in the foreach.
/**
* Retrieve a user by the given credentials.
*
* #param array $credentials
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials)
{
if (empty($credentials) ||
(count($credentials) === 1 &&
→ Str::contains($this->firstCredentialKey($credentials), 'password'))) { ←
return;
}
// First we will add each credential element to the query as a where clause.
// Then we can execute the query and, if we found a user, return it in a
// Eloquent User "model" that will be utilized by the Guard instances.
$query = $this->newModelQuery();
foreach ($credentials as $key => $value) {
→ if (Str::contains($key, 'password')) { ←
continue;
}
if (is_array($value) || $value instanceof Arrayable) {
$query->whereIn($key, $value);
} elseif ($value instanceof Closure) {
$value($query);
} else {
$query->where($key, $value);
}
}
return $query->first();
}
Here's hasValidCredentials from Illuminate\Auth\EloquentUserProvider. The key function here is validateCredentials
/**
* Determine if the user matches the credentials.
*
* #param mixed $user
* #param array $credentials
* #return bool
*/
protected function hasValidCredentials($user, $credentials)
{
$validated = ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
if ($validated) {
$this->fireValidatedEvent($user);
}
return $validated;
}
Here's validateCredentials from the Illuminate\Auth\EloquentUserProvider class. You can see it's again, using by default 'password' as the key name. Let's see what getAuthPassword() looks like.
/**
* Validate a user against the given credentials.
*
* #param \Illuminate\Contracts\Auth\Authenticatable $user
* #param array $credentials
* #return bool
*/
public function validateCredentials(UserContract $user, array $credentials)
{
→ $plain = $credentials['password']; ←
return $this->hasher->check($plain, $user->getAuthPassword());
}
And finally getAuthPassword from the Illuminate\Auth\Authenticatable class. It's just returning the model's 'password' attribute.
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
→ return $this->password; ←
}
Basically, if you want this to work, you need to change a few things about your code.
Use password as the key in attempt()
public function autenticar(Request $request)
{
$attempt = Auth::guard('plataforma')->attempt([
'nombre_usuario' => $request->input('nombre_usuario'),
'password' => $request->input('clave')
]);
if ($attempt) {
return view('web.plataforma');
} else {
dd($attempt);
}
}
Override your Authenticatable model (Usuario)'s getAuthPassword method.
# Usuario model
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return $this->clave;
}

Related

Why is Laravel league/ouath2 token for re-login not recognized

I'm making an app that's using ouath2 login. It works fine when I log in for the first time, but when I try to log in again I get this:Integrity constraint violation: 1062 Duplicate entry.
I've installed league/oauth2/client and called it in my code, but for some reason it's not wokring. I tried everything I could remember, but I don't know what's the problem.
Here are my:
LoginController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Models\User;
use Illuminate\Http\Request;
use League\OAuth2\Client\Token;
use App\Http\Controllers\Controller;
use App\Http\Controllers\VatsimOAuthController;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use League\OAuth2\Client\Provider\GenericProvider;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
/**
* This controller handles authenticating users for the application and
* redirecting them to your home screen. The controller uses a trait
* to conveniently provide its functionality to your applications.
*/
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $provider;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->provider = new VatsimOAuthController;
}
public function login(Request $request)
{
if (! $request->has('code') || ! $request->has('state')) { // User has clicked "login", redirect to Connect
$authorizationUrl = $this->provider->getAuthorizationUrl(); // Generates state
$request->session()->put('vatsimauthstate', $this->provider->getState());
return redirect()->away($authorizationUrl);
}
else if ($request->input('state') !== session()->pull('vatsimauthstate')) { // State mismatch, error
return redirect('/')->withError("Something went wrong, please try again.");
}
else { // Callback (user has just logged in Connect)
return $this->verifyLogin($request);
}
}
protected function verifyLogin(Request $request)
{
try {
$accessToken = $this->provider->getAccessToken('authorization_code', [
'code' => $request->input('code')
]);
} catch (IdentityProviderException $e) {
return redirect('/')->withError("Something went wrong, please try again later.");
}
$resourceOwner = json_decode(json_encode($this->provider->getResourceOwner($accessToken)->toArray()));
// Check if user has granted us the data we need
if (
! isset($resourceOwner->data) ||
! isset($resourceOwner->data->cid) ||
$resourceOwner->data->oauth->token_valid !== "true"
) {
return redirect('/')->withError("We need you to grant us all marked permissions");
}
$this->completeLogin($resourceOwner, $accessToken);
return redirect()->intended('/')->withSuccess('Login Successful');
}
protected function completeLogin($resourceOwner, $token)
{
$account = User::firstOrNew(['id' => $resourceOwner->data->cid]);
if ($resourceOwner->data->oauth->token_valid === "true") { // User has given us permanent access to data
$account->access_token = $token->getToken();
$account->refresh_token = $token->getRefreshToken();
$account->token_expires = $token->getExpires();
$account->name=$resourceOwner->data->personal->name_first;
$account->email=$resourceOwner->data->personal->email;
}
$account->save();
auth()->login($account, true);
return $account;
}
public function logout()
{
auth()->logout();
return redirect('/')->withSuccess('You have been successfully logged out');
}
}
VatsimOAuthController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use League\OAuth2\Client\Token;
use Illuminate\Support\Facades\Auth;
use League\OAuth2\Client\Provider\GenericProvider;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
class VatsimOAuthController extends GenericProvider
{
/**
* #var GenericProvider
*/
private $provider;
/**
* Initializes the provider variable.
*/
public function __construct()
{
parent::__construct([
'clientId' => config('vatsim_auth.id'), // The client ID assigned to you by the provider
'clientSecret' => config('vatsim_auth.secret'), // The client password assigned to you by the provider
'redirectUri' => route('login'),
'urlAuthorize' => config('vatsim_auth.base').'/oauth/authorize',
'urlAccessToken' => config('vatsim_auth.base').'/oauth/token',
'urlResourceOwnerDetails' => config('vatsim_auth.base').'/api/user',
'scopes' => config('vatsim_auth.scopes'),
'scopeSeparator' => ' '
]);
}
/**
* Gets an (updated) user token
* #param Token $token
* #return Token
* #return null
*/
public static function updateToken($token)
{
$controller = new VatsimOAuthController;
try {
return $controller->getAccessToken('refresh_token', [
'refresh_token' => $token->getRefreshToken()
]);
} catch (IdentityProviderException $e) {
return null;
}
}
}
User.php
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use League\OAuth2\Client\Token\AccessToken;
use App\Http\Controllers\VatsimOAuthController;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* Your user model will need to contain at least the following attributes.
*
* #var array
*/
protected $fillable = [
'access_token',
'refresh_token',
'token_expires',
];
/**
* At least the following attributes should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'access_token',
'refresh_token',
'token_expires',
];
/**
* When doing $user->token, return a valid access token or null if none exists
*
* #return \League\OAuth2\Client\Token\AccessToken
* #return null
*/
public function getTokenAttribute()
{
if ($this->access_token === null) return null;
else {
$token = new AccessToken([
'access_token' => $this->access_token,
'refresh_token' => $this->refresh_token,
'expires' => $this->token_expires,
]);
if ($token->hasExpired()) {
$token = VatsimOAuthController::updateToken($token);
}
// Can't put it inside the "if token expired"; $this is null there
// but anyway Laravel will only update if any changes have been made.
$this->update([
'access_token' => ($token) ? $token->getToken() : null,
'refresh_token' => ($token) ? $token->getRefreshToken() : null,
'token_expires' => ($token) ? $token->getExpires() : null,
]);
return $token;
}
}
}

Laravel API validation (different rules depending on route)

I'm currently using Laravel with Infyom to build a backend, one thing that I'm not understanding is how to have multiple rules for validation depending on the API route, for instance, when I'm creating a user, both fields email and role should be provided to the endpoint, but when updating the user (due to login), only the email and password is required to be present. What I want is to have a different set o rules depending on the endpoint being used, is that possible and how? Currently, the endpoint always returns
{
"message": "The given data was invalid.",
"errors": {
"role": [
"The role field is required."
]
}
}
my routes/api.php looks like this
<?php
use Illuminate\Http\Request;
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::post('login', 'TokenAPIController#loginUser');
Route::put('login/updateToken/{id}', 'TokenAPIController#updateToken');
Route::resource('users', 'UserAPIController');
Route::resource('roles', 'RoleAPIController');
Route::resource('roles', 'roleAPIController');
Route::resource('product_variants', 'Product_variantAPIController');
Route::resource('product_images', 'Product_imageAPIController');
Route::resource('product_categories', 'Product_categoryAPIController');
Route::resource('products', 'ProductAPIController');
Route::resource('orders', 'OrderAPIController');
Route::resource('order_products', 'Order_productAPIController');
Route::resource('notifications', 'NotificationAPIController');
Route::resource('factories', 'FactoryAPIController');
Route::resource('statuses', 'StatusAPIController');
My user app/Models/User.php
<?php
namespace App\Models;
use Eloquent as Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model
{
use SoftDeletes;
public $table = 'users';
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';
protected $dates = ['deleted_at'];
public $fillable = [
'name',
'role',
'email',
'password',
'remember_token',
'notification_token',
'factory',
'api_token'
];
/**
* The attributes that should be casted to native types.
*
* #var array
*/
protected $casts = [
'id' => 'integer',
'name' => 'string',
'role' => 'integer',
'email' => 'string',
'password' => 'string',
'remember_token' => 'string',
'notification_token' => 'string',
'factory' => 'integer',
'api_token' => 'string'
];
/**
* Validation rules
*
* #var array
*/
public static $rules = [
'role' => 'required',
'email' => 'required'
];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
**/
public function role()
{
return $this->belongsTo(\App\Models\Role::class, 'role');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
**/
public function factory()
{
return $this->belongsTo(\App\Models\Factory::class, 'factory');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
**/
public function orders()
{
return $this->hasMany(\App\Models\Order::class, 'customer');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
**/
public function order1s()
{
return $this->hasMany(\App\Models\Order::class, 'responsible');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
**/
public function notifications()
{
return $this->hasMany(\App\Models\Notification::class, '"from"');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
**/
public function notification2s()
{
return $this->hasMany(\App\Models\Notification::class, '"to"');
}
}
And finally, my TokenAPIController.php
<?php
namespace App\Http\Controllers\API;
use App\Http\Requests\API\CreateUserAPIRequest;
use App\Http\Requests\API\UpdateUserAPIRequest;
use App\Models\User;
use App\Repositories\UserRepository;
use Illuminate\Http\Request;
use App\Http\Controllers\AppBaseController;
use Response;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;
class TokenAPIController extends AppBaseController
{
/** #var UserRepository */
private $userRepository;
public function __construct(UserRepository $userRepo)
{
$this->userRepository = $userRepo;
}
public function loginUser(UpdateUserAPIRequest $request)
{ /** #var User $user */
$input = $request->all();
if (!isset($input['email'])) {
return $this->sendError('Email is required');
}
if (!isset($input['password'])) {
return $this->sendError('Password is required');
}
$user = User::where('email', $input['email'])
->first();
if (empty($user)) {
return $this->sendError('User not found');
}
$validCredentials = Hash::check($input['password'], $user["password"]);
if ($validCredentials) {
return $this->updateToken($user["id"]);
}
return $this->sendError('No match');
}
public function updateToken($id)
{
// $input = $request->all();
/** #var User $user */
$user = $this->userRepository->find($id);
if (empty($user)) {
return $this->sendError('User not found');
}
$token = Str::random(60);
$user->forceFill([
'api_token' => hash('sha256', $token),
])->save();
return $this->sendResponse($user->toArray(), 'User updated successfully');
}
}
Edit your App\Http\Requests\API\UpdateUserAPIRequest file and adjust the rules it returns from rules.

How to implement Laravel’s Must Verify Email feature in the API registration?

I implemented MustVerifyEmail interface in my user model
class User extends Authenticatable implements MustVerifyEmail
also I made VerificationApi Controller
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Foundation\Auth\VerifiesEmails;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Auth\Events\Verified;
class VerificationApiController extends Controller
{
use VerifiesEmails;
* Mark the authenticated user’s email address as verified.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function verify(Request $request) {
$userID = $request['id'];
$user = User::findOrFail($userID);
$date = date("Y-m-d H:i:s");
$user->email_verified_at = $date; // to enable the “email_verified_at field of that user be a current time stamp by mimicing the must verify email feature
$user->save();
return response()->json('Email verified!');
}
/**
* Resend the email verification notification.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function resend(Request $request)
{
if ($request->user()->hasVerifiedEmail()) {
return response()->json('User already have verified email!', 422);
// return redirect($this->redirectPath());
}
$request->user()->sendEmailVerificationNotification();
return response()->json('The notification has been resubmitted');
}
}
and I made
<?php
namespace App\Notifications;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\URL;
use Illuminate\Auth\Notifications\VerifyEmail as VerifyEmailBase;
class VerifyApiEmail extends VerifyEmailBase
{
/**
* Get the verification URL for the given notifiable.
*
* #param mixed $notifiable
* #return string
*/
protected function verificationUrl($notifiable)
{
return URL::temporarySignedRoute(
'verificationapi.verify', Carbon::now()->addMinutes(60), ['id' => $notifiable->getKey()]
); // this will basically mimic the email endpoint with get request
}
}
in my api.php file I added
Route::get('email/verify/{id}', 'VerificationApiController#verify')->name('verificationapi.verify');
Route::get('email/resend', 'VerificationApiController#resend')->name('verificationapi.resend');
So when i register to my api I get verification email in my mailtrap and when I click the button it says that my email is verified and in my database it changes from null to email_verified_at 2019-05-27 13:04:20 but when I put middleware('verified') on my routes and when I login with user that I have registrated in my postman I get
"message": "Your email address is not verified.",
"exception": "Symfony\\Component\\HttpKernel\\Exception\\HttpException",
my register() and login() functions look like this:
public function register(Request $request, User $user)
{
$phoneRegex = "(06|387)[0-9]{7,8}";
$request->validate([
'first_name' => 'required|string',
'last_name' => 'required|string',
'email' => 'required|string|email|unique:users',
'password' => 'required|string|confirmed',
'phone_number' => 'required|string|min:6',
]);
$user = new User([
'first_name' => $request->first_name,
'last_name' => $request->last_name,
'email' => $request->email,
'password' => bcrypt($request->password),
'phone_number' => $request['phone_number'],
]);
$user->save();
Auth::login($user,true);
$user->sendApiEmailVerificationNotification();
$success['message'] = 'Please confirm yourself by clicking on verify user button sent to you on your email';
return response()->json(['success'=>$success], $this->successStatus);
}
public function login(Request $request)
{
$request->request->add([
'client_id' => env("PASSPORT_CLIENT_ID"),
'client_secret' => env("PASSPORT_CLIENT_SECRET"),
'grant_type' => 'password',
'scope' => '',
]);
$tokenRequest = $request->create('/oauth/token', 'POST', $request->all());
$response = Route::dispatch($tokenRequest);
return $response;
}
can someone help me with this?
I solved this by doing the following:
Create a file
Http > Middleware > EnsureEmailIsVerified.php
with this code
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Contracts\Auth\Factory as Auth;
class EnsureEmailIsVerified
{
/**
* The authentication factory instance.
*
* #var \Illuminate\Contracts\Auth\Factory
*/
protected $auth;
/**
* Create a new middleware instance.
*
* #param \Illuminate\Contracts\Auth\Factory $auth
* #return void
*/
public function __construct(Auth $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $redirectToRoute
* #return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle($request, Closure $next, $guard = null)
{
if (! $request->user($guard)) {
if($request->expectsJson()) {
return response()->json([
'message' => 'You do not have permission to access this feature.',
'errors' => [
'main' => ['The access token is either missing or incorrect.']
]
], 401);
} else {
return redirect(route('login'));
}
} else if
($request->user($guard) instanceof MustVerifyEmail &&
! $request->user($guard)->hasVerifiedEmail()) {
if($request->expectsJson()) {
return response()->json([
'message' => 'You do not have permission to access this feature.',
'errors' => [
'main' => ['Your email address is not verified.']
]
], 403);
} else {
return redirect(route('verification.notice'));
}
}
$this->auth->shouldUse($guard);
return $next($request);
}
}
In the Kernel.php file, change the value for 'verified'
protected $routeMiddleware = [
...
'verified' => \App\Http\Middleware\EnsureEmailIsVerified::class,
]
In the routes > api.php file use verified:api
Route::group(['middleware' => 'verified:api'], function () {
Route::get('/user', function (Request $request) {
return $request->user();
});
});
This works well for me, as I can use the same middleware for both my API and website while still being as generic as possible.
I just added this to my login() function and now it looks like this
public function login(Request $request)
{
$request->request->add([
'client_id' => env("PASSPORT_CLIENT_ID"),
'client_secret' => env("PASSPORT_CLIENT_SECRET"),
'grant_type' => 'password',
'scope' => '',
]);
$tokenRequest = $request->create('/oauth/token', 'POST', $request->all());
$response = Route::dispatch($tokenRequest);
$user = User::where('email', $request->username)->first();
if($user->email_verified_at !== NULL){
$success['message'] = "Login successfull";
return $response;
}else{
return response()->json(['error'=>'Please Verify Email'], 401);
}
}
and now if you did not verify your email you can't login it does not give you your access and refresh token back but I don't have to use my middleware('verified') on my routes so if someone still have better solution I would appreciate it.

Laravel 5 ResetsPasswords for JWTAuth

I am using JWT Authentication and I am trying to setup a Reset Password api functionality using ResetsPasswords.
I have created my own controller for reseting the password to use ResetsPasswords:
namespace App\Http\Controllers\v1;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use App\Models\PdTlogin;
use App\Models\PdTprofessional;
use App\Models\PdTpatientPainkiller;
use App\Models\PdTprofessionalQualifcation;
use App\Models\PdTprofessionalSpeciality;
use Config;
use LbTtradesman_login;
use Auth;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller
{
use ResetsPasswords;
public function resetPassword(request $request)
{
return json_encode($this->reset($request));
}
public function __construct()
{
$this->middleware('guest');
}
}
And I am calling the reset function in ResetsPasswords, here is that full controller:
namespace Illuminate\Foundation\Auth;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Password;
trait ResetsPasswords
{
use RedirectsUsers;
/**
* Reset the given user's password.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse
*/
public function reset(Request $request)
{
//$this->validate($request, $this->rules(), $this->validationErrorMessages());
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
return $response == Password::PASSWORD_RESET
? $this->sendResetResponse($response)
: $this->sendResetFailedResponse($request, $response);
}
/**
* Get the password reset validation rules.
*
* #return array
*/
protected function rules()
{
return [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed|min:6',
];
}
/**
* Get the password reset validation error messages.
*
* #return array
*/
protected function validationErrorMessages()
{
return [];
}
/**
* Get the password reset credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(Request $request)
{
return $request->only(
'email', 'password', 'password_confirmation', 'token'
);
}
/**
* Reset the given user's password.
*
* #param \Illuminate\Contracts\Auth\CanResetPassword $user
* #param string $password
* #return void
*/
protected function resetPassword($user, $password)
{
$user->forceFill([
'password' => bcrypt($password),
'remember_token' => Str::random(60),
])->save();
$this->guard()->login($user);
}
/**
* Get the response for a successful password reset.
*
* #param string $response
* #return \Illuminate\Http\RedirectResponse
*/
protected function sendResetResponse($response)
{
return trans($response);
}
/**
* Get the response for a failed password reset.
*
* #param \Illuminate\Http\Request
* #param string $response
* #return \Illuminate\Http\RedirectResponse
*/
protected function sendResetFailedResponse(Request $request, $response)
{
return ['email' => trans($response)];
}
/**
* Get the broker to be used during password reset.
*
* #return \Illuminate\Contracts\Auth\PasswordBroker
*/
public function broker()
{
return Password::broker('pd_tlogin');
}
/**
* Get the guard to be used during password reset.
*
* #return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard();
}
}
But when I run everything, my password does not get updated. Instead I get this error:
Type error: Argument 1 passed to
App\Http\Controllers\v1\ResetPasswordController::resetPassword() must
be an instance of Illuminate\Http\Request, instance of App\User given,
called in
/var/www/html/my_project/vendor/laravel/framework/src/Illuminate/Foundation/Auth/ResetsPasswords.php
on line 45
I really don't understand this error or what I am doing wrong :( All I know is that my User model is App\Models\PdTlogin with the database table name of pd_tlogin
UPDATE
I have also tried this:
public function resetPassword(request $request)
{
$this->validate($request, [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed',
]);
$credentials = $request->only(
'email', 'password', 'password_confirmation', 'token'
);
$response = $this->passwords->reset($credentials, function($user, $password) {
$user->password = bcrypt($password);
$user->save();
$this->auth->login($user);
});
return json_encode($response);
}
But I got this error:
Undefined property:
App\Http\Controllers\v1\ResetPasswordController::$passwords',
'/var/www/html/my_project/app/Http/Controllers/v1/ResetPasswordController.php
You are invoking resetPassword of the ResetPasswordController instead of invoking resetPassword of the ResetPasswords trait. Change the resetPassword function name in your controller or use an alias for the trait resetPassword function like this:
use ResetsPasswords
{
resetPassword as protected resetUserPassword;
}
Well, It seems you need a json resonse from the reset method. Modify your ResetPasswordController as,
<?php
namespace App\Http\Controllers\v1;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
//...
class ResetPasswordController extends Controller
{
use ResetsPasswords;
protected function sendResetResponse($response)
{
return response()->json(['success' => trans($response)]);
}
protected function sendResetFailedResponse(Request $request, $response)
{
return response()->json(['error' => trans($response)], 401);
}
// removed min:6 validation
protected function rules()
{
return [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed',
];
}
public function __construct()
{
$this->middleware('guest');
}
}
And point your reset route to ResetPasswordController#reset.
return response()->json(['message'=> __('labels.password_updated')]);

Laravel 5.3 dynamically binding validator to custom form request

I'm developing in a system using Laravel 5.3 and I"m trying to update custom validation rules. The architecture is currently as follows:
ProfileStoreRequest --> ProfileValidator
ClientStoreRequest --> ClientValidator
...
What I'm basically trying to do here is to have only one object named "StoreRequest" which will call the correct validator depending on the route which is being called. Here's what I have so far:
In my routes:
Route::group([
'prefix' => 'manage',
'namespace' => 'Manage',
'validators' => [
'manage.profile.storeAjax' => [
'name' => "required|max:40",
'color' => "integer|digits_between:0,7",
'service' => "integer", //digits_between:3,10
'company_id' => "required|integer|exists:companies,id,deleted_at,NULL",
'site_id' => "integer|siteIdExists"
]
]], function () {
Route::post('/site/storeAjax', 'SiteController#storeAjax')->name('manage.site.storeAjax');
Route::post('/company/storeAjax', 'CompanyController#storeAjax')->name('manage.company.storeAjax');
Route::post('/employee/store', 'EmployeeController#store')->name('manage.employee.store');
Route::post('/employee/addProfile', 'EmployeeController#addProfile')->name('manage.employee.addProfile');
Route::post('/employee/removeProfile', 'EmployeeController#removeProfile')->name('manage.employee.removeProfile');
Route::post('/employee/addSite', 'EmployeeController#addSite')->name('manage.employee.addSite');
Route::post('/employee/removeSite', 'EmployeeController#removeSite')->name('manage.employee.removeSite');
Route::post('/message/storeAjax', 'MessageController#storeAjax')->name('manage.message.storeAjax');
Route::post('/profile/storeAjax', 'ProfileController#storeAjax')->name('manage.profile.storeAjax');
Route::post('/timeEntry/storeAjax', 'TimeEntryController#storeAjax')->name('manage.timeEntry.storeAjax');
});
Next is my StoreRequest:
namespace App\Http\Requests;
use App\Http\Validators\ProfileValidator;
use Auth;
//use App\Model\TimeEntry;
use DateUtil;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
class StoreRequest extends AbstractRequest {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize() {
// prj(__METHOD__);
$authorized = parent::authorize();
if ($authorized) {
$user = Auth::user();
if ($user && $user->can('write')) {
return true;
} else {
return false;
}
}
return false;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules() {
parent::rules();
return $this->route()->getAction()['validators'][$this->route()->getName()];
}
/**
* User messages
*
* #return array
*/
public function messages() {
$messages = array_merge(parent::messages(), [
'exists' => 'The selected :attribute is invalid for this time entry id.'
]);
return $messages;
}
public function validate()
{
parent::validate();
}
}
And of course, all of my custom validators are registered using service providers (here's an example with a profileValidator):
profileServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Validator;
class ProfileServiceProvider extends ServiceProvider {
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot() {
Validator::extend('siteIdExists', 'App\Http\Validators\ProfileValidator#validateSiteIdExists');
}
/**
* Register any application services.
*
* #return void
*/
public function register() {
//
}
}
ProfileValidator.php
namespace App\Http\Validators;
use App\Model\Site;
use Mockery\Exception;
class ProfileValidator
{
public function validateSiteIdExists($attribute, $value, $parameters, $validator)
{
if ($value == -1)
return true;
else
{
return Site::where(
[
['id', '=', $value],
['company_id', '=', $validator->getData()['company_id']]
]
)->whereNull('deleted_at')->exists();
}
}
}
So basically, my StoreRequest is capable of loading its validation rules from the route... however, no matter how hard I try, I can't figure how to bind the validator I want. Can anyone help me?

Categories