Working in Laravel Spark and have a custom API endpoint that checks a user credentials but doesn't log them in, just returns the user data.
I have a form request that checks the email and password for being required and then I use
withValidator()
to run some more validation on the password.
public function rules()
{
return [
'email' => 'required|email|exists:users',
'password' => 'required'
];
}
public function withValidator($validator)
{
$validator->after(function ($validator) {
$user = User::where('email', $this->email)->first();
if ( $user && !Hash::check($this->password, $user->password) ) {
$validator->errors()->add('password', 'Incorrect password');
} else {
// Pass the user to the controller
}
});
}
In my controller I want to be able to return the user, but I dont want to run through the process of checking the hash etc.
I would simply like to be able to do:
return $request->user
Or similar.
Is there a way to do this?
Why not just do this in the controller?
$user = User::where('email', $request->email)->first();
If you put this after the validator, you already know the user is valid, otherwise the validator would fail before it got to that point.
Related
I have a client which want to save his data encrypted in the database (email, name etc.). He wants to log in with the email too. I made the functionality to log in with encrypted email but the problem is that after log in I am redirected to a blank page with the url /login when I should be redirected to /business-accounts. If I delete manually the /login from the url I am redirected to the /business-accounts which I need to be redirected. Before doing the ecrypted email authentication everything worked fine.
AuthenticatedSessionController.php
public function store(LoginRequest $request)
{
//check user is validated
User::all()->filter(function ($user) use ($request) {
if($user->email == $request->email){
if($user && $user->status==0){
throw ValidationException::withMessages([
'validation' => 'Account not verified.'
]);
}
//get user email crypted for login
$request->merge(['email' => User::find($user->id)->get_email_crypted()]);
$request->authenticate();
$request->session()->regenerate();
//set user session
UserService::set_session($user);
return redirect()->intended(RouteServiceProvider::HOME);
}
});
}
I printed a dd() before the return and seems like everything is working fine till there.
LoginRequest.php
public function authenticate()
{
$this->ensureIsNotRateLimited();
if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
RateLimiter::hit($this->throttleKey());
throw ValidationException::withMessages([
'email' => __('auth.failed'),
]);
}
RateLimiter::clear($this->throttleKey());
}
RouteServiceProvider.php
public const HOME = '/business-accounts';
Encryption and decryption is made in the User model with get/setEmailAttribute. In the authenticate() method I could see that it is not entering the if where Auth::attempt is located.
I tried to make it work in PasswordResetLinkController too but all I could get is the same blank page with the url /forgot-password and no email received in the inbox.
My Laravel version is 8.x.
L.E. I dumped something before the return redirect() and I saw that in the browser after the login submit I am redirected back to the /login form, so I am thinking that I am getting in a loop or something.
L.E.2.
I somehow resolved this. The thing that I done was changing the crypting method on the email column. I changed the Laravel cripting method with the openssl_crypt function.
User Model
public function setEmailAttribute($value)
{
if (!is_null($value)) {
$this->attributes['email'] = openssl_encrypt($value, "AES-128-ECB", env('EMAIL_ENCRYPT_KEY', false));
}
}
Where the crypting key is located in .env.
AuthenticatedSessionController.php
public function store(LoginRequest $request)
{
//check user is validated
$user = User::where('email', openssl_encrypt($request->email, "AES-128-ECB", env('EMAIL_ENCRYPT_KEY', false)))->first();
if($user && $user->status==0){
throw ValidationException::withMessages([
'validation' => 'Contul nu este verificat'
]);
}
//set email from request to encrypted email
$request->merge(['email' => User::find($user->id)->get_email_crypted()]);
$request->authenticate();
$request->session()->regenerate();
UserService::set_session($user);
return redirect()->intended(RouteServiceProvider::HOME);
}
you can take a look in the log file in /storage/logs/laravel.log for the error message
also, you could change the .env file to show_errors = true and it will show the error in the browser
Use return redirect()->route('your-route-name'); maybe can help you.
I am trying to authenticate a user with the obvious email and password and also if the ban_status is set to 0 in the database.
I have had a look at the newest laravel docs and I have tried it this way in the AuthenticateUsers.php
protected function validateLogin(Request $request)
{
$this->validate($request, [
$this->username() => 'required', 'password' => 'required', 'ban_status' => '0',
]);
}
This does not do anything as far as I can tell and will log in the user regardless whether there ban status is 0 or not, where should I be doing this extra condition?
To build on tam's answer, I added a redirect based on the failed "banned" status because otherwise I would still get logged in, even though the condition was false. Here's the override of the login function that worked for me, placed in LoginController.php :
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$credentials = $this->credentials($request);
if ($this->guard()->attempt($credentials, $request->has('remember')))
{
if ($this->guard()->user()->ban_status === 0) { // ADDED THIS CHECK
return $this->sendLoginResponse($request);
} else { // logout and redirect if failed
$this->guard()->logout();
return redirect()->back()
->withInput($request->only($this->username(), 'remember'))
->withErrors([
$this->username() => 'You have been banned',
]);
}
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
To make a long story short, what you are actually trying to do in the code you posted is to check the ban_status value being passed in from the $request, or in other words the login form.
My understanding of your questions is that this is not really what you want.
Instead, try this:
Override the login method of AuthenticatesUsers by defining it in LoginController, with the following small addition to check for your ban_status:
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($lockedOut = $this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$credentials = $this->credentials($request);
if ($this->guard()->attempt($credentials, $request->has('remember'))) {
if ($this->guard()->user()->ban_status === 0) { // ADDED THIS CHECK
return $this->sendLoginResponse($request);
}
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
if (! $lockedOut) {
$this->incrementLoginAttempts($request);
}
return $this->sendFailedLoginResponse($request);
}
You can also manually authenticate the users:
public function authenticate(Request $request)
{
$password=$request->get('password');
$email=$request->get('email');
if (Auth::attempt(['email' => $email, 'password' => $password,'ban_status'=>0]) )
{
return redirect()->intended('/');
}
else
{
return redirect('/login');
}
}
Rather than override the login() function, as in the accepted answer, it is probably better to override the credentials() function. This function is expected to return an array of values to check for in the database.
When comparing against a fixed value as in the original question, just make an array and merge it in:
protected function credentials(Request $request)
{
return array_merge(
$request->only($this->username(), "password"),
["ban_status" => 0]
);
}
Or, to compare against a dynamic value (e.g. there is an <input type="hidden" name="your_field" value="42"/> in the login form) then you can simply add it to the list of returned request fields.
protected function credentials(Request $request)
{
return $request->only($this->username(), "password", "your_field");
}
Why is this better? The user is never authenticated at all in the system – the database query will not return a result unless all conditions match. In the accepted answer, the user initially passes the login attempt. As user3703567 found out, this can cause issues.
I want use hash class for hash my passwords.
because I want slat password with My policy.
I have controller like this:
public function postLogin(Request $request)
{
$rules = array(
'username' => 'required',
'password' => 'required|min:8'
);
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
return redirect()->back()->withErrors($validator)
->withInput();
} else {
$user=User::where('username',$request['username'])->where('group_id',1)->get()->toArray();
$password=new PasswordController;
$request['password'] = $password->create_password_str($request['username'],$request['password']);
if(isset($user[0]['password'])&&Hash::check($request['password'], $user[0]['password'])){
return redirect('/dashboard');
} else {
return view('auth.login')->with('flag',5);
}
}
}
I use username after login like this
{{Auth::user()->username}}
show me error
Trying to get property of non-object
I add this code before redirect but dont work.
Auth::login($request['username']);
Because you do not use the laravel builtin function so it did not store the user in a SESSION and it throws an error while you try to fetch a user data which actually does not exists. Here's how to authenticate with laravel auth attempt function
if( Auth::attempt(['username' => $username, 'password' => $password]))
{
//redirect to dashboard
} else
{
//invalid credentials
}
Note : Even you do not need to convert your password to hash. laravel is intelligent enough to convert it to hash.
Update: If you want to use custom salt for your project you could checkout this link.
I am fairly new to laravel and I am trying to create a login functionality in laravel 4.2 where the username and password is fetched from the database. I am planning to use this code in the controller but i don't know how to tweak it in such a way that the username and password should be based from a database record
public function postLogin()
{
$credentials = [
'username'=>Input::get('username'),
'password'=>Input::get('password')
];
$rules = [
'username' => 'required',
'password'=>'required'
];
//validating the credentials.
$validator = Validator::make($credentials,$rules);
//in case the credentials are valid. Try to login the user.
if($validator->passes())
{
if(Auth::attempt($credentials))
{
//if successfull redirect the user
return Redirect::to('user/home');
}
//else send back the login failure message.
return Redirect::back()->withInput()->with('failure','username or password is invalid!');
}
//send back the validation errors.
return Redirect::back()->withErrors($validator)->withInput();
}
public function getLogout()
{
Auth::logout();
return Redirect::to('/');
}
Any ideas? Thanks for any help in advance.
You don't need to tweak that code. Default behavior of Auth is to use the eloquent driver which uses the database you configured with your app.
So Auth::attempt($credentials) will use the database table associated (default users table) to authenticate the user with the provided credentials.
You can change the model or table name like opitons in Auth.php file in config directory.
Edit
To validate and login a user manually use the following.
public function postLogin()
{
$credentials = Input::only('username', 'password');
$validator = Validator::make($credentials, [
'username' => 'required',
'password'=>'required'
]);
if($validator->fails())
{
return Redirect::back()->withErrors($validator)->withInput();
}
$user = User::where('SystemUserName', $credentials['username'])->first();
if (! $user || ! Hash::check($credentials['password'], $user->SystemUserPassword)) {
return Redirect::back()->withInput()->with('failure','username or password is invalid!');
}
Auth::login($user);
return Redirect::to('user/home');
}
I have created login form and using Auth method for authorizing user with email and password. Login is done be doLogin function in HomeControler
public function doLogin()
{
$rules = array(
'email' => 'required|email', // make sure the email is an actual email
'password' => 'required|alphaNum|min:3' // password can only be alphanumeric and has to be greater than 3 characters
);
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails()) {
return Redirect::to('login')
->withErrors($validator) // send back all errors to the login form
->withInput(Input::except('password')); // send back the input (not the password) so that we can repopulate the form
} else {
$userdata = array(
'email' => Input::get('email'),
'password' => Input::get('password')
);
if (Auth::attempt($userdata)) {
$id = Auth::id();
return Redirect::to('panel');
} else {
return Redirect::to('login');
}
}
}
In my routes.php file I have created route to get user by id and before that check if user is logged in.
Route::get('panel/{id}', array('before' => 'auth', function($id)
{
$user=User::find($id);
dd($user);
}));
I have faced 2 problems so far:
– How I can create route with get parameters in doLogin function, so that it redirects user in panel/id/ address?
return Redirect::to('panel')->with('id', $id); is not working!
And second problem is that panel/{id} route is checking if user is logged in with 'before' => 'auth', but if I logged in with User id 1 and then opened address panel/2/ it opens the current route. How I can make laravel to check that user id that is logged in mit opens the current route. How I can make laravel to check that user id that is logged in matches the user ID that is requested in route?atches the user ID that is requested in route?
Just extends all of controllers you want to authorize from BaseController.
BaseController could be
class BaseController extends Controller {
public function __construct() {
$this->beforeFilter('auth');
}
}
then forget about it, it works fine.