I want the blocked user can not perform a password reset link, receive an error message and be forwarded to a page. If a user is blocked, a 2 is stored in the table user, active. How can I do that?
I found thiy code from laravel:
/**
* Send a reset link to the given user.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
*/
public function sendResetLinkEmail(Request $request)
{
$this->validateEmail($request);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$response = $this->broker()->sendResetLink(
$request->only('email')
);
return $response == Password::RESET_LINK_SENT
? $this->sendResetLinkResponse($response)
: $this->sendResetLinkFailedResponse($request, $response);
}
No need to overwrite sendResetLinkEmail function, you can just overwrite the validateEmail like this
protected function validateEmail(Request $request)
{
$this->validate($request,
['email' => ['required','email',
Rule::exists('users')->where(function ($query) {
$query->where('active', 1);
})
]
]
);
}
OR
if you want to redirect to custom url then overwrite sendResetLinkEmail function with manual validation like this
public function sendResetLinkEmail(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => ['required', 'email',
Rule::exists('users')->where(function ($query) {
$query->where('active', 1);
})
]
]);
if ($validator->fails()) {
return redirect('some_other_url')
->with('fail', 'You can not request reset password, account is block');
}
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$response = $this->broker()->sendResetLink(
$request->only('email')
);
return $response == Password::RESET_LINK_SENT
? $this->sendResetLinkResponse($response)
: $this->sendResetLinkFailedResponse($request, $response);
}
Related
i'm new to laravel , hope someone could help me with this problem ,
i've created a request class to validate my inputs . But when the validation fails it doesn't return any error messages instead showing a 404 error.
my request class , recoverIdRequest
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class recoverIdRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'dob' => 'required',
'email' => 'required',
];
}
}
and here's my controller : testController
class testController extends Controller
{
/**
*
* #param \App\Http\Requests\recoverIdRequest $request
* #return Illuminate\Http\Response
*/
public function test(recoverIdRequest $request)
{
$validated = $request->validated();
$dob = $request->input('dob');
$new_dob = Carbon::parse($dob)->format('Y-m-d');
$email = $request->input('email');
$exist =Appl_students::where('email', $email)
->whereBetween('dob', [$new_dob, $new_dob])
->select('id', 'first_name')
->first();
if ($exist == null) {
return response()->json(['data' => $exist, 'success' => false, 'message' => "User not found"]);
} else {
$date_of_birth = Carbon::parse($dob)->format('d-m-Y');
$institute =Master::select(
'institution_name', 'website_url', 'institution_place',
'institution_post', 'institution_district', 'institution_pin',
'institution_state', 'institution_phone', 'institution_email')
->first();
return $institute;
Mail::to($email)->send(new RecoverApplicationId($exist->id, $date_of_birth, $exist->first_name, $institute->institution_name));
return response()->json(['data' => $exist, 'success' => true, 'message' => "Application ID has seen sent to registered mail"]);
}
}
}
and this is the response in postman when the validation fails :
routes/api.php
Route::group([ 'prefix'=>'modelTesting', ], function() {
Route::post('test/{id}' [testController::class,'test'])->middleware(['auth:api', 'scope:admin']);
});
Resolved
it was a problem with postman headers,i was able to fix the issue using the following headers :
Accept: application/json
X-Requested-With: XMLHttpRequest
You should follow the naming convention first in all your classes.
As the information not very much clear but it should return 422 error status. It might be the problem that when validation is failed then it is trying to redirect none existence URL. Please check the type of method you are using in postman to call the api. If it not resolved please paste the request data from the postman. And the routes.php
It does not give 404, if the validation process is not successful, validation redirects back to the previous page, in your case it gives 404 because there is no rest API and a previous page ... let's agree here
it's very natural and you just have to write a small validation method for it
try it, add this method to your form request class(recoverIdRequest) and try again
/**
* Returns validations errors.
*
* #param Validator $validator
* #throws HttpResponseException
*/
protected function failedValidation(Validator $validator)
{
// you can debug with dd() in this method
if ($this->wantsJson() || $this->ajax()) {
throw new HttpResponseException(response()->json($validator->errors(), 422));
}
parent::failedValidation($validator);
}
second step you should change handler
app/exceptions/Handler.php
public function render($request, Exception $e)
{
if ($request->ajax() || $request->wantsJson())
{
$json = [
'success' => false,
'error' => [
'code' => $e->getCode(),
'message' => $e->getMessage(),
],
];
return response()->json($json, 400);
}
return parent::render($request, $e);
}
I have the controllers below to allow the user login with laravel auth system but when the user clicks in the button "Login" I get the following error:
Argument 1 passed to Illuminate\Auth\SessionGuard::attempt() must be of the type array, object given, called in C:\laragon\www\AGRIAPP\projet investisseur\AgriApp_Investor\AgriAppInvestor\vendor\laravel\framework\src\Illuminate\Foundation\Auth\AuthenticatesUsers.php on line 82
When I refresh the page I log in so I wanted to solve this problem
According to the documentation, the attempt function takes an array and a bool
LoginController.php
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function showLoginForm()
{
return view('auth.login');
}
protected function credentials(Request $request)
{
$credentials = array(
'slug' => $request->slug,
'password' => $request->password,
'statut' => 1,
);
if(Auth::attempt( $credentials,false ))
{
return Redirect::to( '/admin/home' );
}
}
public function username()
{
return 'slug';
}
protected function authenticated()
{
$user = auth()->user();
$user->online = true;
$user->save();
if ($user->rule->pluck( 'name' )->contains( 'abonne' )) {
return Redirect::to( '/admin-dashboard' );
}
return Redirect::to( '/admin/home' );
}
public function logout()
{
$user = Auth::user();
$user->online=false;
$user->save();
Auth::logout();
return redirect('/');
}}
AuthController.php
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->filled('remember')
);
}
/**
* Get the needed authorization credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(Request $request)
{
return $request->only($this->username(), 'password');
}
You have overridden the credentials() method but you're not returning anything from it.
Change your credentials method to:
protected function credentials(Request $request)
{
return [
'slug' => $request->slug,
'password' => $request->password,
'statut' => 1,
];
}
I realise that you were trying to authenticate the user inside the credentials method but you don't need to as, in this case, the method calling it is doing the same.
The reason your redirect didn't work either is because the calling method wasn't returning it, so your user was getting logged in but you were actually passing the redirect response to the attempt method which is what caused your error.
Also, I'm not sure if statut is a typo or not?
If you're using laravel 8+ all you have to do is to modify your credential function
protected function credentials(Request $request)
{
if(Auth::attempt($request->all())) {
return Redirect::to( '/admin/home' );
}
}
I changed the login function a bit, that the user can only log in with his username and his email if his email address was confirmed by a sent email.
what do I want to do
If the email address has not yet been confirmed, I would like to redirect the user to a page to confirm his email address. If the table "users, active" has a 1, the address has been confirmed.
Currently I have problems logging in with the username. Does anyone recognize a mistake?
How can I implement that? Does anyone have a similar code?
/**
* Get the needed authorization credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(Request $request)
{
$field = filter_var($request->get($this->username()), FILTER_VALIDATE_EMAIL)
? $this->username()
: 'username';
return [
$field => $request->get($this->username()),
'password' => $request->password,
];
}
/**
* Validate the user login request.
*
* #param \Illuminate\Http\Request $request
* #return void
*/
protected function validateLogin(Request $request)
{
$this->validate($request, [
$this->username() => [
'required', 'string',
Rule::exists('users')->where(function ($query){
$query->where('active', true);
})
],
'password' => 'required|string',
], $this->validationError());
}
New loginController
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| 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.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/iboard';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => ['logout', 'userLogout']]);
}
/**
* Get the needed authorization credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(Request $request)
{
$field = filter_var($request->get($this->username()), FILTER_VALIDATE_EMAIL)
? $this->username()
: 'username';
return [
$field => $request->get($this->username()),
'password' => $request->password,
];
}
public function login(Request $request)
{
$this->validateLogin($request);
if (Auth::once($this->credentials($request))) { //use auth once so that it will not create auth session
$user = Auth::user();
if($user->active){
Auth::login($user); //now create auth session, check
return redirect('/iboard'); //redirect to dashboard url
}else{
return redirect('email_confirm')->with('fail', 'Please confirm your email'); //redirect to email confirm page
}
}
return redirect()->back()->with('fail', "Invalid username or password");
}
public function userLogout()
{
Auth::guard('')->logout();
return view('/exit');
}
}
You can try the below code for your login, assuming you have validateLogin and credentials functions in the same controller because the below login action used both of these function. Check details here
public function login(Request $request)
{
$this->validateLogin($request);
if (Auth::once($this->credentials($request))) { //use auth once so that it will not create auth session
$user = Auth::user();
if($user->active == 1){
Auth::login($user); //now create auth session
return redirect('dashboard'); //redirect to dashboard url
}else{
return redirect('email_confirm')->with('error', 'Please confirm your email'); //redirect to email confirm page
}
}
return redirect()->back()->with('error', "Invalid username or password");
}
I have a login functionality from Web and also from API. I have created one Request file where I have written rules for this. For web, it is working perfectly and given output as expected but when I use it in API controller it redirects me to the login page, it should return JSON response.
One more thing, I want to add extra parameter "status" as it is failed or succeeds.
Here is my code
Request File
public function rules()
{
return [
'username' => 'required',
'password' => 'required'
];
}
API controller
public function login(Request $request)
{
$response = array();
$validator = Validator::make($request->all(), [
'username' => 'required',
'password' => 'required'
]);
if ($validator->fails()) {
$response['status'] = false;
$response['message'] = $validator->messages();
return Response::json($response);
}
try {
$username = trim($request->username);
$password = trim($request->password);
$isAuth = $this->userRepository->login($username, $password);
if ($isAuth) {
$user = Auth::user();
$response['status'] = true;
$response['message'] = Lang::get('custom.auth_success');
$response['user_detail'] = $user;
} else {
$response['status'] = false;
$response['message'] = Lang::get('auth.failed');
}
} catch (\Exception $e) {
$response = array();
$response['status'] = false;
$response['message'] = Lang::get('custom.something_wrong');
}
return Response::json($response);
}
and Web controller
public function checkAuth(UserAuthenticate $request)
{
try {
$username = trim($request->username);
$password = trim($request->password);
$isRemember = false;
if (isset($request->remember) && $request->remember == 'on') {
$isRemember = true;
}
$isAuth = $this->userRepository->login($username, $password, $isRemember);
if ($isAuth) {
return redirect('programs');
} else {
return redirect('login')->withInput()->withErrors(['username' => Lang::get('auth.failed')]);
}
} catch (\Exception $e) {
return redirect('login')->withInput()->withErrors(['error' => Lang::get('custom.something_wrong')]);
}
}
Route/web.php
Route::group(['middleware' => ['guest']], function () {
Route::get('login', ['as' => 'login', 'uses' => 'Front\UserController#login']);
});
Route/api.php
Route::post('user/authenticate', 'API\UserController#login');
I looked for the solutions but didn't found anything
Edit: if you want to use extends Request for both validators do the web validation through ajax
Since you're using passport you already have the token so you can skip login
For api your validator needs to extend Request instead of FormRequest
You can't use the same validator, because the web validator extends FormRequest and that return html. Two validators are necessary, there is no way around it.
use App\Http\Requests\Request;
class YourApiRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{}....
In your normal web request you would have
use Illuminate\Foundation\Http\FormRequest;
class YourWebRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return \Auth::check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{....
In Handler.php you need to add something to the render method (if you return json from your api)
If you do not prefix your routes with api/ then figure out how to check if you are in api
if (strpos($prefix, 'api') !== false) {
if ($exception instanceof ValidationException) {
return response()->json(['success' => false, 'error' => $exception->errors(), 'data' => null], 200);
}
return response()->json(['success' => false, 'error' => $exception->getMessage(), 'data' => null], 200);
}
You may try to over ride the Laravel form request validation's failedValidation() method.
public function failedValidation(Validator $validator)
{
//wantsJson() that checks Accept header of the request and returns TRUE if JSON was requested.
if ($this->wantsJson()) {
throw new HttpResponseException(response()->json(["response" => [
'msg' => $validator->errors()->all(),
]]));
}
}
[Not tested on api calls]
I made a route in the api file that allow everybody to create users :
Route::post('users', 'UserController#addUser');
When I called it in postman without using request validation it works. But when I created my request file and use it, Laravel return a NotFoundHttpException.
Here's my request file :
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UserAddRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'user_id' => 'required|numeric',
'name' => 'required|string',
'email' => 'required|string',
'password' => 'required|string'
];
}
}
public function addUser(UserAddRequest $request){
$user = new User;
$user->instance_user_id = $request->input('user_id');
$user->name = $request->input('name');
$user->email = $request->input('email');
$user->password = $request->input('password');
$user->save();
}
There is no form because it needs to be send directly to the server with post method. I declared my route in routes/api.php and I call it with the url /api/users The api in that case doesn't need to check credentials.
I solved my problem :
The NotFoundHttpException was raised because I didn't send my parametters correctly and Laravel doesn't where to redirect me back. When I send directly the request to the server there is no url declared for where I'm coming.