Laravel 5 customizing built in login redirect - laravel

I am customizing laravel 5's built in login so that it would redirect to three different paths according to the type column which i added to the users table, i tried altering the handle function of RedirectIfAuthenticated middleware. but it seems that it always finds the home URI.
here is my edited middleware
public function handle($request, Closure $next)
{
if ($this->auth->check() && $this->auth->user()->type == 'patient') {
// return redirect('/home');
return 'PATIENT VIEW';
} elseif ($this->auth->check() && $this->auth->user()->type == 'doctor') {
return 'DOCTOR VIEW';
} elseif ($this->auth->check() && $this->auth->user()->type == 'nurse') {
return 'NURSE VIEW';
}
return $next($request);
}
Im new to laravel 5 and i would really appreciate any help and explanations

RedirectIfAuthenticated is being misused here. That middleware is for when an authenticated user tries to access a page that should only be accessed by guests. For example, if I am a user and I try to view the login or registration forms, it doesn't let me.
I would not mess with the authentication itself... some of it is easily customizable but what you're trying to do is not. I would just let Laravel authenticate them first and then handle what to do after.
/home is the default route users are taken to when they login. Move your if checks to that route controller method. Better yet... if you set things up right you don't need any checks at all.
class HomeController {
public function index()
{
$user = \Auth::user();
return view($user->type . '.dashboard');
}
}
Now you just need views named patient/dashboard.blade.php, doctor/dashboard.blade.php, etc. If you have more complex logic then you might want an actual redirect
return redirect('home/' . $user->type);
Define routes for each of those types
Route::get('home/patient', 'PatientController#dashboard');
Route::get('home/doctor', 'DoctorController#dashboard');
Route::get('home/nurse', 'NurseController#dashboard');
And then do whatever you need to in those controller methods.

Check out the docs in Authentication section
Basically what you need is:
Create the auth routes at app/Http/routes.php:
// Authentication routes...
Route::get('auth/login', 'Auth\AuthController#getLogin');
Route::post('auth/login', 'Auth\AuthController#postLogin');
Create the login form view:
<!-- resources/views/auth/login.blade.php -->
<form method="POST" action="/auth/login">
{!! csrf_field() !!}
<div>
Email
<input type="email" name="email" value="{{ old('email') }}">
</div>
<div>
Password
<input type="password" name="password" id="password">
</div>
<div>
<input type="checkbox" name="remember"> Remember Me
</div>
<div>
<button type="submit">Login</button>
</div>
</form>
Manually Authenticate users app/Http/Controllers/Auth/AuthController.php:
<?php
namespace App\Http\Controllers;
use Auth;
use Illuminate\Routing\Controller;
class AuthController extends Controller
{
/**
* Handle an authentication attempt.
*
* #return Response
*/
public function authenticate()
{
if (Auth::attempt(['email' => $email, 'password' => $password])) {
if (Auth::user()->type == 'patient'){
return redirect()->intended('patientDashboard');
}
if (Auth::user()->type == 'doctor'){
return redirect()->intended('doctorDashboard');
}
}
}
}
Or if you want to keep the logic under RedirectIfAuthenticated middleware you could just fix your code:
public function handle($request, Closure $next)
{
if ($this->auth->check())
{
//we have a logged user check if it's patient
if($this->auth->user()->type == 'patient'){
return new RedirectResponse(url('/patient'));
}else if($this->auth->user()->type == 'doctor'){
return new RedirectResponse(url('/doctor'));
}
}
return $next($request);
}
Also you should check out this Entrust package.

Related

Laravel login features

I'm working on Laravel task and struggling to add a login feature. Register and validation features seem work well, but can't login even if i put correct user_name and pass_word. also old helper function is not working as well.
i am a very beginner of Laravel and I know my code is messy and not coherent. But need to get this task done. appreciate if you help me solve this!
So here are files of my task. when i tried to login it always goes to this page.
<?php
use App\Http\Controllers\RegisterController;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('users/list', 'App\Http\Controllers\UserController#getUser');
Route::get('register', [RegisterController::class, 'create'])->middleware('guest');
Route::post('register', [UserController::class, 'register'])->middleware('guest');
Route::get('login', [UserController::class, 'loginView']);
Route::post('login', [UserController::class, 'login']);
<?php
namespace App\Http\Controllers;
use App\Http\Requests\UserLoginRequest;
use App\Http\Requests\UserRegisterRequest;
use App\Models\User;
use App\Services\UserService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class UserController extends Controller
{
private $userService;
public function __construct(
UserService $userService
) {
$this->userService = $userService;
}
public function getUser() {
$users = User::all();
return view('users/list')
->with('users', $users);
}
public function register(UserRegisterRequest $request)
{
$this->userService->registerUser($request->user_name, $request->pass_word);
return redirect('users/list');
}
public function loginView()
{
return view('users/loginView');
}
public function login(Request $request)
{
$validatedData = $request->validate([
'user_name' => ['required'],
'pass_word' => ['required'],
]);
if (Auth::attempt($validatedData)) {
$request->session()->regenerate();
return redirect('users/list');
}
return back()->withErrors([
'user_name' => 'wrong username'
]);
}
}
<main>
<h1>Login!</h1>
<form action="login" method="POST">
#csrf
<div>
<label for="user_name">
User_name
<input type="text" name="user_name" id="user_name" value="{{ old('user_name') }}" >
</label>
#error('user_name')
<div class="error">{{ $message }}</div>
#enderror
</div>
<div>
<label for="pass_word">
Password
<input type="password" name="pass_word" id="pass_word" value="{{ old('pass_word') }}">
</label>
#error('pass_word')
<div class="error">{{ $message }}</div>
#enderror
</div>
<div>
<button type="submit">
Submit
</button>
</div>
</form>
</main>
<?php
namespace App\Services;
use Illuminate\Database\Eloquent\Collection;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
class UserService
{
/**
*
*
* #param string $name
* #param string $email
* #param string $pass_word
* #return void
*/
public function registerUser($user_name, $pass_word) : void
{
$user = new User();
$user->user_name = $user_name;
$user->pass_word = Hash::make($pass_word);
$user->save();
}
}
enter image description here
First, if you want to redirect using back() helper to another controller method, you should put ->withInput or ->onlyInput('user_name').
back()->withErrors([
'user_name' => 'wrong username'
])->onlyInput('user_name');
or
back()
->withErrors([
'user_name' => 'wrong username'
])->withInput();
You may dump the errors on the view because probably it comes from the password error may be?

Laravel Fortify Logout Redirect

Hello guys is there any ways to redirect the logout function of Fortify?
<div class="nav-link" id="nav-bar-logoutbutton">
<form method="POST" action="{{ route('logout') }}">
#csrf
<button class="btn btn-secondary btn-sm" type="submit">Logout</button>
</form>
</div>
this is my blade logout
You can do the following:
Create a new LogoutResponse class and implement your redirect logic into the toResponse method:
"app/Http/Responses/LogoutResponse.php"
<?php
namespace App\Http\Responses;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Laravel\Fortify\Contracts\LogoutResponse as LogoutResponseContract;
use Symfony\Component\HttpFoundation\Response;
class LogoutResponse implements LogoutResponseContract
{
/**
* Create an HTTP response that represents the object.
*
* #param Request $request
*
* #return Response
*/
public function toResponse($request)
{
return $request->wantsJson()
? new JsonResponse('', 204)
: redirect('www.example.com');
}
}
Now you can bind the new response into the service container in the boot method of your FortifyServiceProvider:
"app/Providers/FortifyServiceProvider.php"
public function boot()
{
$this->app->singleton(
\Laravel\Fortify\Contracts\LogoutResponse::class,
\App\Http\Responses\LogoutResponse::class
);
}
In your config/fortify.php, add:
'redirects' => [
'logout' => 'login',
],
Just create a new post request in your routes/web.php
Route::post('logout', [ClientController::class, 'logout'])->name('logout');
Now in your controller, create a function to handle the request, make sure to include the Auth class at the top.
use Auth;
/* Process the logout request */
public function logout(Request $request) {
Auth::logout();
return redirect('/login')->with(['msg_body' => 'You signed out!']);
}
Instead of /login, you can redirect to anywhere.

Laravel 5.x - Custom middleware for authenticating a PIN

I have read the middleware documentation for Laravel yet I feel like im misunderstanding something.
What I want to do is simply to authenticate everytime before being able to view a book.
E.g. If I go to '\book\funnybook' redirect => '\book\funnybook\authenticate' (which says enter a PIN number)
The problem I am having is:
I dont know where to place the redirect function (middleware? controller?)
I dont know where to retrieve the value of the user input and compare it with the database value. Meaning again where should I place it? in the middleware or controller? and how would my view call the function?
In post function of authenticate in Controller.. Similar below
public function postPin(Request $request){
...
...
return Redirect::intended();
}
Let's create a minimal example of such middleware so you'll be able to improve it from there.
From your explanation I assume that every book will have its own pin. You can change that behavior if you want something else.
First, let's create our routes for view/authenticate books:
routes/web.php
use Illuminate\Support\Facades\Route;
Route::group(['prefix' => 'book'], function () {
// view authenticated book
Route::get('{bookSlug}', 'BookController#view')->name('book.view');
// show book authenticate form
Route::get('{bookSlug}/authenticate', 'BookController#showAuth')->name('book.authenticate');
// handle user input, authenticate book
Route::post('{bookSlug}/authenticate', 'BookController#authenticate');
});
Let's also add pattern for bookSlug parameter (update boot method as shown):
app/Providers/RouteServiceProvider.php
class RouteServiceProvider extends ServiceProvider {
// ...
public function boot()
{
Route::pattern('bookSlug', '[A-Za-z0-9_-]+');
parent::boot();
}
// ...
}
Now, let's create the middleware:
php artisan make:middleware CheckPin
Every middleware has handle method that allows it to check for something and either allow request to pass next (by calling $next() closure), or stop request processing by throwing an error or redirecting to another URL.
Here, we'll check book authentication status in session. It will be stored there by auth form. If book isn't authenticated yet, we'll redirect to the auth form.
app/Http/Middleware/CheckPin.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Route;
class CheckPin {
public function handle($request, Closure $next)
{
$bookSlug = Route::current()->parameter('bookSlug');
// check whether book has been authenticated
// redirect to auth form otherwise
if(!session("books.$bookSlug")) {
return redirect()->route('book.authenticate', compact('bookSlug'));
}
return $next($request);
}
}
We have to register our middleware in Kernel.php (update it as shown):
app/Http/Kernel.php
use App\Http\Middleware\CheckPin;
//...
class Kernel extends HttpKernel {
//...
protected $routeMiddleware = [
//...
'pin' => CheckPin::class, //
];
protected $middlewarePriority = [
//...
CheckPin::class,
];
//...
}
Let's create our simple views. Create resources/views/book folder and put views there.
View for displaying book content:
resources/views/book/view.blade.php
<h1>View book → {{ $bookSlug }}</h1>
<p>Some content</p>
View for display book auth form:
resources/views/book/auth.blade.php
<h1>Authenticate → {{ $bookSlug }}</h1>
<form method="post" action="{{ route('book.authenticate', compact('bookSlug')) }}">
#csrf
<label for="pin">Enter pin:</label>
<input type="password" name="pin" id="pin" required autofocus />
<button class="submit">Authenticate</button>
#error('pin')
<p>
<i><b>Error:</b> {{ $message }}</i>
</p>
#enderror
</form>
And finally, let's create book controller that will show books, auth form, and handle user input.
php artisan make:controller BookController
app/Http/Controllers/BookController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class BookController extends Controller {
public function __construct()
{
// "pin" middleware will protect all methods except #showAuth and #authenticate
$this->middleware('pin')->except(['showAuth', 'authenticate']);
}
function view(Request $request, string $bookSlug)
{
return view('book.view', compact('bookSlug'));
}
function showAuth(Request $request, string $bookSlug)
{
return view('book.auth', compact('bookSlug'));
}
// handles user input, checks for valid pin
// redirects to the authenticated book or back to the form
function authenticate(Request $request, string $bookSlug)
{
$pin = $request->input('pin');
// Check book pin here; for testing purpose: pin should equal book slug
if($pin === $bookSlug) {
session()->put("books.$bookSlug", 1);
return redirect()->route('book.view', compact('bookSlug'));
}
return redirect()->back()->withErrors(['pin' => ['Invalid pin']]);
}
}
It works like this:
When user opens some book, for example book/funny it will be redirected to book/funny/authenticate where they can enter pin and authenticate the book. If the pin is valid, then user is redirected back to book/funny URL, otherwise the error is shown.
That's all. You can extend this example to better suit your needs: add more methods to BookController, check book pin from database etc.

Laravel: How to make sure a user goes to role-specific home view after registration and after login?

I have created a custom multi-auth system in laravel-5.8 for a college website where every user registers for a specific role: Admin, Faculty, or HOD(Head of Department).
I am making use of the controllers and views which we get after running
php artisan make:auth
Upon registering, all the users are redirecting to default home page, regardless of their roles. The 3 roles are being stored in the Users table as 0, 1, and 2 under column role. I modified the Users table which comes by default.
My login mechanism works well. Users are redirected to the home page of their role. Here is how I do it:
LoginController.php
public function login(Request $request){
if(Auth::attempt(['PID' => $request->PID, 'password' => $request->password])){
$user = User::where('PID',$request->PID)->first();
if($user->role == '0'){
return redirect('home');
}
else{
if($user->role == '1'){
return redirect('hodhome');
}
else{
return redirect('adminhome');
}
}
}
return redirect()->back();
}
This is the route used upon the POST request from login.blade.php
Route::post('/login/custom', 'auth\LoginController#login')->name('login.custom');
But every time I register a new user, it takes users to the faculty home page route, even when they're admins or HODs. Here's the register mechanism:
RegisterController.php (Just showing relevant functions below)
use RegistersUsers;
protected $redirectTo = '/home';
public function __construct()
{
$this->middleware('guest');
}
//validator function and create function after this line
I have tried to make it work properly by doing this: Changing the variable redirectTo to a function.
//an idea: replace "protected $redirectTo = '/home';" by...
protected function redirectTo(array $data){
if($data['role']=='0'){ return redirect('home'); }
elseif($data['role']=='1'){ return redirect('hodhome'); }
else return redirect('adminhome');
}
But it doesn't work, because I seem to be missing something.
Another bummer is the fact that after login, users can access home pages of other roles. the middleware('auth') in my routes helps protect against accessing the URLs when not logged in, but it doesn't stop logged in users from accessing other home pages.
Here are the routes to the home pages:
Auth::routes();
//-------------------MULTI AUTH SYSTEM------------------------------------------
Route::post('/login/custom', 'auth\LoginController#login')->name('login.custom');
Route::get('/home', 'HomeController#index')->name('home');
route::get('/adminhome', function () {
return view('adminhome');
})->middleware('auth');
route::get('/hodhome', function () {
return view('hodhome');
})->middleware('auth');
//----------------------------------------------------------------------------
The default welcome.blade.php too redirects logged in users to faculty's home page:
#if (Route::has('login'))
<div class="top-right links">
#auth
Home
#else
Login
#if (Route::has('register'))
Register
#endif
#endauth
</div>
#endif
How do I make sure users go to the right home pages upon a new registration and when logging in?
How do I make sure home page of one role stays inaccessible to other roles?
EDIT 1:
After incorporating changes suggested by #N69S, This is what's happening:
pages have become role specific.
one role can not access pages of another role, and unauthenticated users can not view any pages except the welcome page.
That solution worked. But when an illegal access to a URL is attempted, an error has to be generated.
But instead, user is being sent to the welcome page. This page has only one link in the top right corner, called "HOME". This link does not work when either admin or HOD user is logged in because it routes to '/home' as shown:
//welcome.blade.php
<body>
<div class="flex-center position-ref full-height">
#if (Route::has('login'))
<div class="top-right links">
#auth
Home
#else
Login
#if (Route::has('register'))
Register
#endif
#endauth
</div>
#endif
<div class="content">
<div class="title m-b-md text-center">
COLLEGE ADMINISTRATION <br> SYSTEM
</div>
</div>
</div>
</body>
How do I change this view file to send logged in user to his role's HOME?
One complete and correct solution would be to separate the entities (HOD, Admin, User) and configure the auth for each one (auth:hod, auth:admin, auth)
Another solution would be to make 3 separate middleware and group your routes with one of them accordingly.
btw, redirectTo() method does not take parameters. From Illuminate\Foundation\Auth\RedirectsUsers trait
/**
* Get the post register / login redirect path.
*
* #return string
*/
public function redirectPath()
{
if (method_exists($this, 'redirectTo')) {
return $this->redirectTo();
}
return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
}
---------------Edit
For the 3 middleware solution, you can use the command php artisan make:middleware Admin, this will create the Class file app/Http/ Middleware/Admin.php.
in the handle method, you can do something like
public function handle($request, Closure $next)
{
if(auth()->user() && auth()->user()->role == 2){
return $next($request);
}
return redirect(‘login’)->with(‘error’,’You have not admin access’);
}
and do the same for the HOD
To use it like authin the routes, add the middleware in the kernel App\Http\Kernel.php in $routeMiddleware
protected $routeMiddleware = [
//....,
//....,
'admin' => \App\Http\Middleware\Admin::class,
];

Post route not working and returns no errors in laravel

I am working on a multistep form in laravel. When I click next button after filling the first page, the same page is refreshed and it doesn't go to next page. It was working fine properly but suddenly it is working like this (getting refreshed).
My web.php has a route like this:
Route::get('register', 'registercontroller#page1')
Route::post('register', 'registercontroller#postpage1')
in register controller, I have defined functions like this
public function page1(Request $request)
{
$request->session()->flush();
$info = $request->session()->get('Register');
return view('register',compact('Register', $info));
}
public function postpage1(Request $request)
{
/* business logic here */
}
My register.blade.php has form like this:
<form action="register" method="POST">
#csrf
<input type="text" name="name">
...
...
...
</form>
However when I tried route in web.php like this:
Route::post('register', 'registercontroller#test')
and in registercontroller function as
public function test(){
echo "test";
}
It works fine...
All this I am working on local environment using xampp
Please help someone.. thanks
In your register controller you will need to return another view or redirect:
public function page1(Request $request)
{
$request->session()->flush();
$info = $request->session()->get('Register');
return view('register',compact('Register', $info));
}
public function postpage1(Request $request)
{
/* business logic here */
return redirect('register-2');
// or
return view('register-2');
}

Resources