how do I do an authentication triage in Laravel 6.12? - laravel

I am using laravel 6.12 using the Authentication artisan command
php artisan ui vue --auth
I have been following https://laraveldaily.com/auth-login-how-to-check-more-than-just-emailpassword/ website . I would like to know the steps needed to authenticate with a triage i.e company, email address and password.
I am receiving a duplicate when I add company name, it thinks this is the email address. Where do you change this? And I am recieving the following error.
BadMethodCallException
Method App\Http\Controllers\Auth\LoginController::company does not exist.
$credentials = $request->only($this->username(), 'password');
$credentials = array_add($credentials, 'company');
I need to Verify the Company name as part of the authentication process. with email, password & Company. Does anyone know how to authenticate using three authentication credentials?
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}
'''

Note: The tutorial you linked shows a bad way of logging in a User using a raw SQL query!. Please use a more standard way.
To login a user using multiple properties do something like this in your Controller method:
public function login(Request $request)
{
//... request validation logic
//take only what is needed to verify login
$credentials = request(['company', 'email', 'password']);
//verify login
if (!Auth::attempt($credentials)) {
return response()->json([
'message' => 'Invalid password'
], 401);
}
//Login user, as you're using Vue I assume you use either JWT or Passport
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
$token->save();
return response()->json([
'access_token' => $tokenResult->accessToken,
'token_type' => 'Bearer',
]);
}

Related

Laravel: Using multiple columns for authentication

I have a Laravel 6 application.
In a typical application, the user would just specify their email, where the email is unique.
However, in my application, I have 2 columns in the User model that is used to authenticate users.
app_id
email
unique(app_id, email)
So in order to login, we need to pass both an app_id and an email, along with the password. The same email could be used across different app_ids.
How would I achieve this?
The default login actions provided by Auth::routes() are the following:
Route::get('login', 'Auth\LoginController#showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController#login');
This is the default login function, part of the AuthenticatesUsers trait used by the LoginController:
/**
* Handle a login request to the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*
* #throws \Illuminate\Validation\ValidationException
*/
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 (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
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.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
There are a few ways to approach this.
Option 1: Override login function in LoginController
# app/Http/Controllers/Auth/LoginController.php
public function login(Request $request)
{
// add more stuff like validation, return the view you want, etc.
// This is barebones
auth()->attempt($request->only(['app_id', 'login', 'password']);
}
Option 2: Override both the validateLogin and the credentials functions in LoginController
# app/Http/Controllers/Auth/LoginController.php
protected function validateLogin(Request $request)
{
$request->validate([
'app_id' => 'required|string',
'email' => 'required|string',
'password' => 'required|string',
]);
}
/**
* Get the needed authorization credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(Request $request)
{
return $request->only('app_id', 'email', 'password');
}

Retrieve user by Sanctum plainTextToken

How to retrieve the 'logged in' user from a Sanctum token.
For logging in I have the following method
public function login(Request $request)
{
if (Auth::attempt($request->toArray())) {
/* #var User $user */
$user = $request->user();
$token = $user->createToken('web-token')->plainTextToken;
return response()->json([
'user' => $user,
'token' => $token,
], Response::HTTP_OK);
}
}
Now for logging out I use a custom method.
public function logout(Request $request)
{
dd($request->user()); // <- Always returns null
}
I want to revoke the token, but I don't know how to retrieve the currently logged in user. Obviously for logging out I send the Authorization header with the Bearer and plainTextToken as value.
for sure you have first add token in bearer token
and to get user out of sanctum middleware now token is optional
$user = auth('sanctum')->user();
than log out
if ($user) {
$user->currentAccessToken()->delete();
}
note : this delete only current token
if u need all tokens use
foreach ($user->tokens as $token) {
$token->delete();
}
If you don't use the default Sanctum middleware, you can get the user from the plain text token as follow:
use \Laravel\Sanctum\PersonalAccessToken;
/** #var PersonalAccessToken personalAccessToken */
$personalAccessToken = PersonalAccessToken::findToken($plainTextToken);
/** #var mixed $user */
$user = $personalAccessToken->tokenable;
Since you're sending the bearer/token to the Logout url you can try to override the logout function of the AuthenticatesUsers:
/**
* Log the user out of the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
$this->guard()->logout();
$request->user()->tokens()->delete();
return redirect('/');
}
simply add the route within middleware('auth:sanctum') grouped routes
then from inside the targeted function you can get user like this auth()->user()
or if you just want to log out the user you can revoke token like this
$request->user()->currentAccessToken()->delete();

NotFoundHttpException with my Request file on api route

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.

Checking if user account is confirmed by email code With unnecessary logging in Laravel

I have a laravel project, where I try implement checking if user account is confirmed by activation code from user's email:
public function SignIn(Request $request){
if(Auth::attempt(['email' => $request['email'], 'password' => $request['password']])) {
if(Auth::user()->status==false){
Auth::logout();
Session::flash('activationError','First please active your account');
return back();
}
return redirect()->route('showDashboardWelcome');
}
else{
Session::flash('loginError','Your username and password are wrong');
return back();
}
}
In above code there is function from controller to Sign in user. This function check if the user email and password are correct and if user has confirmed account($status variable from user model with two boolean values) by email code.
If account is not confirmed by user I must logout user from account, because function attempt start simultaneously user's session. Is there any possible way to do this operation without starting a user session and then logout user?
I would be grateful for help. Best regards
Add a middleware to directly query the users table and check the status field. If not verified redirect away to the page showing the message. For example:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckVerified
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = User::where('email', $request->email)->first();
if (!user->status) {
return redirect()->back()->with('not verified');
}
return $next($request);
}
}
You can pass as many parameters to attempt([]) as you want. So here you can add 'status' to the array like this
if(Auth::attempt([
'email' => $request['email'],
'password' => $request['password'],
'status' => true
])) {
}
Every single parameter you pass to that array has to be met for the Auth::attemp() to start the session.

Trying to reset Passwords in Lumen

I am trying to implement password reset feature in Lumen but could not succeed.
Lumen has access to things like Laravel's PasswordBroker and PasswordManager but I am not able to use this and succeed. Is there any solution for this.
I literally just figured this out last night and wrote a blog about it:
http://www.imjohnbon.com/password-resets-in-lumen/
Hopefully it can at least get you on the right track.
Ok, so I just got this working myself, with Lumen 5.6. (I've upgraded to 5.8, still works, no changes made).
These are the changes I had to make to my code. I had to tweak a few things to suit my system, but this might help someone else.
Routes
I wanted two routes.
Send reset password email
GET auth/resetpassword?email=fred#example.com
Reset Password
PUT auth/resetpassword?token=281...b&username=fred&password=banana&password_confirmation=banana
Composer
To send the user an email, the following Laravel packages are needed:
composer require illuminate/mail "^5.6"
composer require illuminate/notifications "^5.6"
Config files
Some extra config file are needed:
config/auth.php
config/mail.php
I just copied these over from Laravel 5.6, no changes made. I also added the mail variables into my .env file.
bootstrap/app.php
These new files need to be registered in the app:
$app->configure('auth');
$app->configure('mail');
$app->register(Illuminate\Notifications\NotificationServiceProvider::class);
$app->register(\Illuminate\Mail\MailServiceProvider::class);
$app->alias('mailer', \Illuminate\Contracts\Mail\Mailer::class);
$app->withFacades();
Database
I used the default Laravel password_resets table:
Schema::create('password_resets', function (Blueprint $table) {
$table->string('email')->index();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
Now the real changes to the code.
Based on the code from Illuminate\Foundation\Auth\SendsPasswordResetEmails and Illuminate\Foundation\Auth\ResetsPasswords.
AuthController
use Illuminate\Auth\Passwords\PasswordBrokerManager;
use Illuminate\Support\Facades\Password;
use Laravel\Lumen\Routing\Controller;
use Illuminate\Http\Request;
class AuthController extends Controller
{
// 1. Send reset password email
public function generateResetToken(Request $request)
{
// Check email address is valid
$this->validate($request, ['email' => 'required|email']);
// Send password reset to the user with this email address
$response = $this->broker()->sendResetLink(
$request->only('email')
);
return $response == Password::RESET_LINK_SENT
? response()->json(true)
: response()->json(false);
}
// 2. Reset Password
public function resetPassword(Request $request)
{
// Check input is valid
$rules = [
'token' => 'required',
'username' => 'required|string',
'password' => 'required|confirmed|min:6',
];
$this->validate($request, $rules);
// Reset the password
$response = $this->broker()->reset(
$this->credentials($request),
function ($user, $password) {
$user->password = app('hash')->make($password);
$user->save();
}
);
return $response == Password::PASSWORD_RESET
? response()->json(true)
: response()->json(false);
}
/**
* Get the password reset credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(Request $request)
{
return $request->only('username', 'password', 'password_confirmation', 'token');
}
/**
* Get the broker to be used during password reset.
*
* #return \Illuminate\Contracts\Auth\PasswordBroker
*/
public function broker()
{
$passwordBrokerManager = new PasswordBrokerManager(app());
return $passwordBrokerManager->broker();
}
}
User model
use Illuminate\Auth\Passwords\CanResetPassword as CanResetPasswordTrait;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordInterface;
use Illuminate\Notifications\Notifiable;
class User extends Model implements CanResetPasswordInterface
{
use CanResetPasswordTrait;
use Notifiable;
...
}

Resources