My Laravel authentication works perfectly. I included password change feature. After changing the password,the login works fine for all users except the first user(uid="1"). Only the default password hash works well for this user. For other password hashes the login attempt fails. My codes are given below:
User Controller Signin
public function postSignin() {
if (Auth::attempt(array('email'=>Input::get('email'), 'password'=>Input::get('password')))) {
return Redirect::to('users/dashboard')->with(array('message' => 'You are now logged in!', 'email' => Input::get('email')));
} else {
return Redirect::to('users/login')
->with('message', 'Your username/password combination was incorrect')
->withInput();
}
}
Table Schema
Schema::create('users', function($table)
{
$table->increments('id');
$table->string('firstname', 20);
$table->string('lastname', 20);
$table->string('email', 100)->unique();
$table->string('password', 255);
$table->string('remember_token', 255);
$table->timestamps();
});
Password Change Controller function
public function postUpass() {
$user = User::find(Input::get('uid'));
if((Input::get('password'))==(Input::get('passconf'))){
$user->password = Hash::make(trim(Input::get('password')));
$user->save();
echo "Done";
//echo Hash::make(trim(Input::get('password')));
}
else {
echo "Check Passwords Again";
}
Someone please help me with this.
I can't comment yet, so I have to ask for your view by posting an answer. Though I would like to also suggest changing the way you are accessing the user in the postUpass function as that could easily be changed by the end user to update another user's password.
//change this
$user = User::find(Input::get('uid'));
//to this
$user = Auth::user();
//since the user needs to be logged in
//to change their password anyway
Also, are you saying that once you post to the postUpass function you are always being returned the 'Check passwords again' notice?
Related
My database has below structure
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique()->nullable();
$table->string('phone')->unique()->nullable();
$table->timestamp('email_verified_at')->nullable();
$table->timestamp('phone_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
DB::statement('ALTER TABLE users ADD CONSTRAINT chk_phone_or_email CHECK (email IS NOT NULL OR email IS NOT NULL);');
}
Basically I have two fields phone and email that can be null but both of then cannot be null. A user can pass either their phone or email but this is passed to the backend as username. With this I need to attempt to login with either and if successful, return token
Below is my code
public function login(ServerRequestInterface $request)
{
$usernames = ['phone', 'email'];
for ($i = 0; $i < sizeof($usernames); $i += 1){
$credentials = ['password' => request()->get('password')];
$credentials[$usernames[$i]] = request()->get('username');
if (Auth::guard('web')->attempt($credentials)) {
return $this->withErrorHandling(function () use ($request) {
return $this->convertResponse(
$this->server->respondToAccessTokenRequest($request, new Psr7Response)
);
});
}
}
return response()->json([
'message' => 'Invalid username or password'
], 401);
}
If I login with valid email and password, I am able to login but if I try to login using phone and password, I get unauthorised,
How can I resolve this?
You can check for users with queries and login with Auth
https://laravel.com/docs/8.x/authentication#authenticate-a-user-instance
for example in your controller:
public function login(ServerRequestInterface $request)
{
$username = request()->get('username');
$password = request()->get('password');
$user = User::where('phone', $username)->orWhere('email', $username)->first();
if ($user === null || !Hash::check($password, $user->password)) {
return response()->json([
'message' => 'Invalid username or password'
], 401);
}
Auth::guard('web')->login($user);
// ...
}
I found below, hope it helps someone,
We can override findForPassport function in the users model to achieve this
public function findForPassport($identifier)
{
return $this->orWhere('email', $identifier)
->orWhere('phone', $identifier)
->orWhere('username', $identifier)
->first();
}
}
See Customizing the Username field
I am on Laravel with Jetstream, I am using responses to redirect a user, once after a user registers himself. I am successfully able to redirect users whenever a user registers. Only admins can create users or invite them. So whenever I create a user from the admin panel, it redirects me to the route('frontend.dashboard') which can only be viewed by the user with a client role. So as I am logged in as an administrator, it throws me a status error 404.
How can I omit the redirection part when an administrator is registering an account. So a user is only redirected whenever he himself registers.
RegisterResponse.php
class RegisterResponse implements RegisterResponseContract
{
public function toResponse($request)
{
if(Auth::user()->hasAnyRoles(['Administrator', 'Employee'])) {
return redirect()->route('backend.dashboard');
}
return redirect()->route('frontend.dashboard');
}
You can use middleware to restrict user to redirect different routes.
Otherwise you can create two tables named "permissions" and "features" in your database.
Table columns should be like this:
- Table(Permissions):
Schema::create('permissions', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('user_id');
$table->unsignedInteger('feature_id');
$table->timestamps();
});
- Table(Features):
Schema::create('features', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
Now make a helper function like this which will check if the particular user has access to redirect to the particular route.
**
Helper function:
**
function has_permission($feature_name)
{
$user = Auth::user();
if($user->role->name == 'admin' ){
$status = True;
}else{
$feature = Feature::where('name', $feature_name)->first();
$status = Permission::where([['user_id', $user->id],['feature_id', $feature->id]])->exists();
}
return $status;
}
So, now you can add condition in your Controllers every functions which redirect to a page like this:
if (!has_permission('shipments')) {
$notification=array(
'message' => 'Sorry ! You do not have permission',
'alert-type' => 'warning'
);
Thank you.Happy coding
I have made a middleware for admins
And I applied it in my routes.
So the problem when the user is admin he can go to users page and change his permissions and the page keeps redirecting and breaks when he clicks change permission to his profile :
ERR_TOO_MANY_REDIRECTS
my method to change user to admin :
public function admin($id){
$user = User::findOrFail($id);
$user->admin = 1;
$user->save();
session()->flash('success','Changed to admin');
return redirect()->back();
}
And to change user to Author :
public function notAdmin($id){
$user = User::findOrFail($id);
$user->admin = 0;
$user->save();
session()->flash('success','Changed to Normal');
return redirect()->back();
}
So how I can prevent the logged in user from changing his permissions?
I'm really confused about this.
Thank you
Redirect the user if he tries to change his own permissions by using
Auth->id() and comparing with $id so that if these things match then he is trying to change his own permission.
public function admin($id){
if(Auth->id() == $id) {
session()->flash('error','Permission denied');
return redirect()->back();
}
$user = User::findOrFail($id);
$user->admin = 1;
$user->save();
session()->flash('success','Changed to admin');
return redirect()->back();
}
I have a problem that I wanted to create a reactivate option for users, but after trying several times, it is not working and I am confused.
here is the middleware (original version):
public function handle($request, Closure $next)
{
if (!Auth::check()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('/');
}
}
else
{
$user = Auth::user();
if (!$user->activated) {
$activation = action('Auth\AuthController#getActivationMail', ['username' => $user->username]);
Auth::logout();
return redirect()->guest('auth')
->withErrors(array('message' => 'Please activate your account. Re-send your activation by clicking <a href=' . $activation . '>here</a>.'));
}
else if (!$user->enabled) {
Auth::logout();
return redirect('/auth')->withErrors(array('message' => 'Your account has been deactivated. Please email ... for any inquiries.'))->withInput();
// I tried to add the same method as the above if statement but not working here
}
$user->runDailyNotifications();
}
return $next($request);
}
I wanted to update my database using this way:
$user = Auth::user();
$user->enabled = 1;
$user->save();
which should be working fine.
I am new to Laravel. At first, I added these code in the middleware (which is a mistake).
After trying a bit I know it is impossible for it to work (when users click login twice they will log in after deactivating their account). Now I'm just wondering how could I achieve that since I kept getting error messages from everywhere. Thank you for the help!
I have done email confirmation and resend confirmation in one of my older projects. I've done the email confirmation validation in the post login check in the LoginController. Let me post you some snippets which might help you.
// Overwrite the authenticated method in LoginController
protected function authenticated(Request $request, $user)
{
if ($user->isBanned()) {
$this->logout($request);
flashError('Your account has been banned.');
return back();
}
if (!$user->isEmailConfirmed()) {
$this->logout($request);
flashWarning('Email confirmation pending. Click here to resend confirmation email.');
return back();
}
return redirect()->route($this->redirectRoute);
}
public function resendConfirmationEmail(Request $request, User $user)
{
//resend confirmation email
}
public function confirmEmail(Request $request, $token)
{
// Validate the token and update the user email confirmation status
}
Model
public function isBanned()
{
return (bool) $this->banned;
}
public function isEmailConfirmed()
{
return (bool) $this->confirmed;
}
Route
Route::get('confirm/resend/{user}', 'Auth\RegisterController#resendConfirmationEmail')->name('confirm.resend');
Route::get('confirm/email/{token}', 'Auth\RegisterController#confirmEmail')->name('confirm.email');
I'm trying to get the a login with mfa to work. I'm using the https://github.com/antonioribeiro/google2fa package.
Basically the user-migration looks like this
class CreateUsersTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up() {
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password', 60);
$table->rememberToken();
$table->string('google2fa_secret');
$table->boolean('useMfa')->default(false);;
$table->timestamps();
});
}
...
If the user has not yet activated mfa I create a new secret every time the user opens the profile page.
if(!$user->useMfaToken()){
$google2fa = new Google2FA();
$user->google2fa_secret = $google2fa->generateSecretKey();
$user->save();
$google2fa_url = $google2fa->getQRCodeGoogleUrl(
'DatenPro.de',
$user->email,
$user->google2fa_secret
);
}
If the user enters the secret for finalizing the activation of mfa this will be executed:
public function saveMfa(){
$user = \Auth::user();
$secret = \Input::get('secret');
$google2fa = new Google2FA();
$valid = $google2fa->verifyKey($user->google2fa_secret, $secret);
if($valid){
$user->useMfa = true;
$user->save();
return redirect()->back()->withMessage('mfa sucessfully activated');
}
...
Now I'm working on the login with a mfa-token. I want that the user has the option to enter the token at the login page, if he has already activated it, otherwise if the mfa-Checkbox is deselected the "secret" text-input is hidden.
Email: __________
Password: __________
Use Mfa: [x]
Secret: __________
Where do I have to put the checks of the mfa token? I have read about it to check it through a middleware and a session-variable, but this seems kind of wrong.
Just figured it out before posting.
You can implement a "authenticated"-method in the AuthController.
This could look like this:
public function authenticated($request, $user){
if($user->useMfaToken()){
$secret = \Input::get('secret');
$google2fa = new Google2FA();
$validMfaToken = $google2fa->verifyKey($user->google2fa_secret, $secret);
}else{
$validMfaToken = true;
}
if($validMfaToken){
return redirect()->intended('dashboard');
}
Auth::logout();
return redirect($this->loginPath)
->withInput($request->only('email', 'remember'))
->withErrors([
'secret' => 'mfa token was not corret',
]);
}