Modify native authentication in Laravel 5.2 - laravel

I'm using the out of the box authentication in Laravel 5.2 (using artisan command make:auth). It works like a charm.
Thing is, I'd like to restrict login for only active users (deleted_at = NULL).
However when using soft deletes I cannot retrieve other models with a user_id foreign key (allthough the user has been deleted, I still have to access the users information).
What would be a good approach?
An alternative I came up with is to use an "active" boolean column instead of a "deleted_at" date column. This way, I could filter only user with "active"=TRUE and would have no problem whith foreign keys.
In this case, how could I restrict users to login only if "active" is set to TRUE?
Cheers!

The trait Laravel uses to authenticate in controllers has a handleUserWasAuthenticated() method. It checks for another method called authenticated() (which isn’t defined by default) and calls that before fully authenticating a user and letting them access your application. Therefore, if you define this method in your own AuthController, you can do any post-authentication checking such as if the user is active.
class AuthController
{
public function authenticated($request, $user)
{
if (! $user->is_active) {
// Throw exception, display error etc.
}
return redirect()->intended($this->redirectPath());
}
}

You can always pass any extra parameters to the Auth::attempt() method, like so:
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// Redirect to required route/url
}
From what I understand, you can do something similar for the deleted_at field as well.

In Auth\AuthController.php, add authenticated() function
use Auth;
class AuthController extends Controller
{
.
.
.
public function authenticated($request, $user) {
if (! $user->active) {
Auth::logout();
return redirect('login')->withErrors([
$this->loginUsername() => 'Your '.$this->loginUsername().' is not active. Please contact Administrators'
]);
}else {
return redirect()->intended($this->redirectPath());
}
}

Related

I have problem when i logout from admin "Trying to get property 'id' of non-object" using laravel

I am trying to logout from admin but unfortunately, I face error Trying to get property 'id' of non-object How to fix this error? please help me thanks.
public function index(){
$user_permission = Users_Permissions::with('user')
->Where('user_id',Auth::user()->id)
->paginate(5);
return view('index',compact('user_permission'));
}
The problem is clear. When you log out, then Auth::user() is null. so there is no id . You can solve the issue like this.
public function index()
{
if (Auth::check()) {
$user_permission = Users_Permissions::with('user')->Where('user_id',Auth::user()->id)
->paginate(5);
return view('index',compact('user_permission'));
} else {
// The condition when no user logged in
// For an example
return redirect('login'); // This is just an example
}
For that, use try & catch in every function, and use auth middleware for specific routes while you are working with auth users.
so that specific routes are required to use auth, so you don't need to check in every function. auth is always present.
Route::middleware('auth')->group(function () {
Route::get('logout', 'AuthController#logout');
});
or else you can use middleware in a controller too,
class AuthController extends Controller
{
public function __construct(){
$this->middleware(['guest'])->except('logout');
}
}
It's because after logout you don't have user ID, so in this situation the User is null, and you want to get the if from null object. you can change this part of code like below
Users_Permissions::with('user')->Where('user_id',Auth::user()->id ?? 0)
then you pass the error. you can put every number or null in query based on your needs.

how do i use index_number and date_of_birth for frontend login in laravel with the user having to register first

I am creating a student project in Laravel. I have created all my models including the student model. I want to use the student_number(index_number) and the students date_of_birth from the student model as login credential for the front end view instead of the default user login(email and password). I do not want users to register before they can login as in the default laravel welcome page.
There are so many tricks to do this.
Laravel ships with Authentication
In your Login Controller you can do this:
public function login() {
$user = User::where('index_number', request('index_number'))->first();
if($user->birthday != request('birthday')) {
return 'Invalid Credentials';
}
\Auth::login($user);
return 'login success'
}
Try Auth::attempt() method,
pass your credentials same as your user table.
for example;
public function login(Request $request)
{
$credentials = ['student_number' => $request->student_number,'date_of_birth' => $request->date_of_birth,'active' => 'Y'];//Database to check in User table
if (Auth::attempt($credentials)) {
return redirect('student/dashboard');
}
else
{
Session::flash('mess', "Invalid Credentials , Please try again.");
return redirect()->back();
}
}
Don't forgot to use
use Auth;
Hope this works

redirect to different views in laravel logged in users based on role mentioned by using if condition in laravel controller

In laravel i have student,parent ,employee(Teacher,Librarian,warden) roles with different permissions...based on user role it should redirect to different blade files when user logged in..my problem is if user parent or student it is redirecting to different dashboards but whenever user is teacher or other it does not logged in but in users table already user exist.
below is my LoginController code
LoginController.php:
public function login(Request $request){
if(Auth::attempt([
'email'=>$request->email,
'username'=>$request->username,
'password'=>$request->password,
]))
{
$user=User::where('username',$request->username)->first();
$usertype=$user->user_type;
$username=$user->username;
$roles=DB::table('roles')->where('id','=',$usertype)->first();
$rolename=$roles->role_name;
if($rolename=="student"){
$student=DB::table('students')->where('stud_adm_id','=',$username)->first();
$classid=$student->class_id;
$sectionid=$student->section_id;
$class=DB::table('classtables')->where('id',$classid)->first();
$section=DB::table('sections')->where('id',$sectionid)->first();
return view('studentdashboard',compact('student','class','section'));
}elseif($rolename=="Teacher"){
$employeedetails=DB::table('employees')->where('employee_fname','=',$username)->first();
return view('teacherdashboard',compact('employeedetails'));
}
elseif($rolename=="parent"){
$parentdetails=DB::table('parents')->where('mother_phone','=',$username)->first();
$stateid=$parentdetails->state;
$state=DB::table('states')->where('state_id','=',$stateid)->first();
return view('parentdashboard',compact('parentdetails','state'));
}
}else{
return redirect()->back();
}
}
my roles are mentioned in role table and that id stored in users table
Thanks in advance...
You better create a middleware to check user role, and based on the role redirect user to different pages!
Run the command below to create a middleware that checks user's role.
php artisan make:middleware CheckRoleMiddleware
The command will create a file under App\Http\Middleware named CheckRoleMiddleware this class will come a predefined method handle() there you can place the logic that checks user's role and redirects them to different pages example:
<?php namespace App\Http\Middleware;
use Closure;
class CheckRoleMiddleware {
public function handle($request, Closure $next)
{
//User role is admin
if ( Auth::check() && Auth::user()->isAdmin() )
{
return $next($request);
}
//If user role is student
if(Auth::check() && auth()->user()->role === 'student')
{
return view('studentDashboard');
or route('routeName');
}
//If user role is teacher
if(Auth::check() && auth()->user()->role ==='teacher')
{
return view('teacherDashboard');
or route('routeName');
}
//default redirect
return redirect('home');
}
}
And don't forget to add CheckRoleMiddleware to App\Http\Kernel.php
protected $routeMiddleware = [
'auth' => 'App\Http\Middleware\Authenticate',
'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
'user-role' => 'App\Http\Middleware\CheckRoleMiddleware', // this line right here
];
Lets just ignore everything about how this stuff should work and how it does by default and take what you have.
Do you see a problem here:
if ($rolename == "student")
elseif ($rolename == "Teacher")
elseif ($rolename == "parent")
If not, lets try it this way:
student
Teacher
parent
Which one is not like the others? And which one was the one that "was not working" correctly?
I would like to assume you have these roles named in a consistent fashion, so Teacher should be teacher.
You can do all of what you want to do with the default LoginController by overriding a method or two.
You should not be returning views from processing routes. POST REDIRECT GET. POST comes in, return a REDIRECT, that causes a GET request (which most likely is going to return a view).
For validating the login credentials:
protected function validateLogin(Request $request)
{
$this->validate($request, [
'email' => '...',
'username' => '...',
'password' => '...',
]);
}
For what credentials should be used from the request:
protected function credentials(Request $request)
{
return $request->only('email', 'username', 'password');
}
The response to return after successful authentication:
protected function authenticated(Request $request, $user)
{
// do your role checking here
// return a redirect response to where you want that particular user type to go
// return redirect()->route(...);
}
Everything related to building the views and gathering that data is its own route. All you have to do is return a redirect for the login flow. Where you redirect to is responsible for gathering the data needed to display a view.

How to logout a user from API using laravel Passport

I'm currently using 2 projects. 1 front end (with laravel backend to communicate with API) and another laravel project (the API).
Now I use Laravel Passport to authenticate users and to make sure every API call is an authorized call.
Now when I want to log out my user, I send a post request to my API (with Bearer token) and try to log him out of the API (and clear session, cookies,...)
Then on the client I also refresh my session so the token is no longer known. Now when I go back to the login page, it automatically logs in my user. (Or my user is just still logged in).
Can someone explain me how to properly log out a user with Laravel passport?
Make sure that in User model, you have this imported
use Laravel\Passport\HasApiTokens;
and you're using the trait HasApiTokens in the User model class using
use HasApiTokens
inside the user class.
Now you create the log out route and in the controller,
do this
$user = Auth::user()->token();
$user->revoke();
return 'logged out'; // modify as per your need
This will log the user out from the current device where he requested to log out. If you want to log out from all the devices where he's logged in. Then do this instead
$tokens = $user->tokens->pluck('id');
Token::whereIn('id', $tokens)
->update(['revoked'=> true]);
RefreshToken::whereIn('access_token_id', $tokens)->update(['revoked' => true]);
Make sure to import these two at the top
use Laravel\Passport\RefreshToken;
use Laravel\Passport\Token;
This will revoke all the access and refresh tokens issued to that user. This will log the user out from everywhere. This really comes into help when the user changes his password using reset password or forget password option and you have to log the user out from everywhere.
You need to delete the token from the database table oauth_access_tokens
you can do that by creating a new model like OauthAccessToken
Run the command php artisan make:model OauthAccessToken to create the model.
Then create a relation between the User model and the new created OauthAccessToken Model , in User.php add :
public function AauthAcessToken(){
return $this->hasMany('\App\OauthAccessToken');
}
in UserController.php , create a new function for logout:
public function logoutApi()
{
if (Auth::check()) {
Auth::user()->AauthAcessToken()->delete();
}
}
In api.php router , create new route :
Route::post('logout','UserController#logoutApi');
Now you can logout by calling posting to URL /api/logout
This is sample code i'm used for log out
public function logout(Request $request)
{
$request->user()->token()->revoke();
return response()->json([
'message' => 'Successfully logged out'
]);
}
Create a route for logout:
$router->group(['middleware' => 'auth:api'], function () use ($router) {
Route::get('me/logout', 'UserController#logout');
});
Create a logout function in userController ( or as mentioned in your route)
public function logout() {
$accessToken = Auth::user()->token();
DB::table('oauth_refresh_tokens')
->where('access_token_id', $accessToken->id)
->update([
'revoked' => true
]);
$accessToken->revoke();
return response()->json(null, 204);
}
I am using Laravel 6.12.0, below function is working for me.
public function logout(Request $request){
$accessToken = Auth::user()->token();
$token= $request->user()->tokens->find($accessToken);
$token->revoke();
$response=array();
$response['status']=1;
$response['statuscode']=200;
$response['msg']="Successfully logout";
return response()->json($response)->header('Content-Type', 'application/json');
}
This is my first post.. and i find a clean solution (Laravel last Version)
/**
* Logout api
*
* #return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
if (Auth::check()) {
$token = Auth::user()->token();
$token->revoke();
return $this->sendResponse(null, 'User is logout');
}
else{
return $this->sendError('Unauthorised.', ['error'=>'Unauthorised'] , Response::HTTP_UNAUTHORIZED);
}
}
Below is the simplest way I found to do it.
1. USE database SESSION INSTEAD OF file SESSION
Official documention
php artisan session:table
php artisan migrate
Replace SESSION_DRIVER=file by SESSION_DRIVER=database in your .env file.
2. DELETE USER SESSION RIGHT AFTER LOGIN
After a user is redirected to your frontend and logs in to finally get a token, you probably call a route in api/routes.php to get the user information, that's where I'm closing the user backend session before sending back user information to the frontend:
Route::middleware('auth:api')->get('/user', function (Request $request) {
// Close user session here
Illuminate\Support\Facades\DB::table('sessions')
->whereUserId($request->user()->id)
->delete();
return $request->user();
});
3. REVOKE TOKENS AT LOGOUT
Then, to "log out" (actually, revoke tokens) the user from the frontend, you just need to call another route to revoke the token and refresh_token:
Route::middleware('auth:api')->post('/logout', function (Request $request) {
// Revoke access token
// => Set oauth_access_tokens.revoked to TRUE (t)
$request->user()->token()->revoke();
// Revoke all of the token's refresh tokens
// => Set oauth_refresh_tokens.revoked to TRUE (t)
$refreshTokenRepository = app('Laravel\Passport\RefreshTokenRepository');
$refreshTokenRepository->revokeRefreshTokensByAccessTokenId($request->user()->token()->id);
return;
});
You may prefer to put these two closures in the UserController.
Hope help someone:
if (Auth::check()) {
$request->user()->tokens->each(function ($token, $key) {
$token->delete();
});
}
Good Luck.
I use this in my project to logout from multiple device.
public function logout(Request $request, $devices = FALSE)
{
$this->logoutMultiple(\Auth::user(), $devices);
return response()->json([], 204);
}
private function logoutMultiple(\App\Models\User $user, $devices = FALSE)
{
$accessTokens = $user->tokens();
if ($devices == 'all') {
} else if ($devices == 'other') {
$accessTokens->where('id', '!=', $user->token()->id);
} else {
$accessTokens->where('id', '=', $user->token()->id);
}
$accessTokens = $accessTokens->get();
foreach ($accessTokens as $accessToken) {
$refreshToken = \DB::table('oauth_refresh_tokens')
->where('access_token_id', $accessToken->id)
->update(['revoked' => TRUE]);
$accessToken->revoke();
}
}
Try this code to help you to logout from passport authentication.
Route::post('/logout', function(){
if (Auth::check()) {
Auth::user()->AauthAcessToken()->delete();
}
return response()->json([
'status' => 1,
'message' => 'User Logout',
], 200);
});
check whether your model contains OauthAccessToken which needs to connect with the database oauth_access_tokens. The access token is stored in the database table oauth_access_tokens. and makes a relation from users to oauth_access_tokens.
public function AauthAcessToken(){
return $this->hasMany(OauthAccessToken::class);
}
You can use following code to remove to token for logged in user.
$request->user()->token()->revoke();
If you want to learn about this in-depth then watch this tutorial:
https://www.youtube.com/watch?v=UKSQdg1uPbQ
public function logout(Request $request)
{
$request->user()->token()->revoke();
if ($request->everywhere) {
foreach ($request->user()->tokens()->whereRevoked(0)->get() as $token) {
$token->revoke();
}
}
return response()->json(['message' => 'success']);
}

auth attempt failing in Laravel 5.4

I have some post about auth attempt failure but my case seems to be different. Still in dev phase so my password is in plain text. I try to login but i keep getting false and so redirected back to login page.
The error message says username/password does not match but dd reveals that both email and password are correct.
What could be responsible for this failure? PS: it's my first time working with laravel
web.php
Route::post('/login', 'AuthController#authenticate');
Route::get('/', 'PostController#index');
AuthController
public function auth()
{
//dd($request);
// attempt to login the user
if (! auth()->attempt(request(['email', 'password']))) {
return back()->withErrors([
'message' => 'Username/Password does not macth'
]);
}
return redirect('/');
}
PostController
public function index()
{
$posts = Post::latest()->limit(3)->get();
return view('post.index', compact('posts'));
}
Use this code in your User model and the password will be hashed automatically only if it needs:
public function setPasswordAttribute($value)
{
if( \Hash::needsRehash($value) ) {
$value = \Hash::make($value);
}
$this->attributes['password'] = $value;
}
and change your password after, so you have the hashed password in the database
Not sure i understand... but if you are using the Laravel Authentication (php artisan make:auth) you will not be storing the password in plain text... so if you are setting the password directly in your db it will not work as it will check the password field in the db with the assumption that it is stored with a dbcrypt hash...
So if you are using the default auth that comes with laravel, use the registration form to create your user account
Since it's your first time working with laravel i would recommend taking a look at https://laracasts.com/series/laravel-from-scratch-2017/episodes/17 as it covers the auth concept and gives you a quick walkthrough on setting up user auth

Resources