As a checklogin function in my Controller I have
public function checkLogin(Request $request)
{
//if the validation rule isn't passed it will be redirected to login form with validation error
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|min:3'
]);
$user_data = array(
'email' => $request->get('email'),
'password' => $request->get('password'),
);
if (Auth::attempt($user_data)) {
return redirect('/successlogin');
//user will be redirected to successlogin method
} else {
return back()->with('error', 'Wrong Login Details');
//by using back() he will be redirected to the previous location
}
}
And I added a $table->boolean('is_admin')->default(0); column to my model
Also I've tried to make a middleware. Something like
IsAdmin.php
public function handle($request, Closure $next)
{
if (Auth::user()) {
if (Auth::user()->is_admin) {
return $next($request);
}
return Redirect::to('successlogin');
}
}
But it throws me an error
"Call to a member function send() on null"
Thanks a lot in advance!
Related
I made a UserController which generats an accessToken when a user registered succesfully on a page.
class UserController extends Controller
{
/**
* Login Method: in here we call Auth::attempt with the credentials the user supplied.
* If authentication is successful, we create access tokens and return them to the user.
* This access token is what the user would always send along with all API calls to have access to the APIs.
* Register Method: like the login method, we validated the user information,
* created an account for the user and generated an access token for the user.
*/
public function login()
{
$credentials = [
'email' => request('email'),
'password' => request('password')
];
if (Auth::attempt($credentials)) {
$success['token'] = Auth::user()->createToken('MyApp')->accessToken;
return response()->json(['success' => $success]);
}
$status = 401;
$response = ['error' => 'Unauthorized'];
return response()->json($response, $status);
}
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required',
'email' => 'required|email',
'password' => 'required',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 401);
}
$input = $request->all();
$input['password'] = bcrypt($input['password']);
$user = User::create($input);
$success['token'] = $user->createToken('MyApp')->accessToken;
$success['name'] = $user->name;
return response()->json(['success' => $success]);
}
public function getDetails()
{
return response()->json(['success' => Auth::user()]);
}
}
My problem is that I want to remove the token when the user logs out but I dont know how to remove the access token from the user.
logout function in my UserController
public function logout()
{
Auth::user()->tokens->each(function($token, $key) {
$token->delete();
});
return response()->json([
'message' => 'Logged out successfully!',
'status_code' => 200
], 200);
}
When I test it with postman with the GET route: http://127.0.0.1:8000/api/logout. Am I missing something?
UPDATE
Here s my api.php file:
Route::resource('categories', 'App\Http\Controllers\CategoryController');
Route::post('register', 'App\Http\Controllers\UserController#register');
Route::post('login', 'App\Http\Controllers\UserController#login');
/**
* We can group the routes we need auth for
* under common middleware. It secures our routes
*/
Route::group(['middleware' => 'auth:api'], function(){
Route::get('logout', 'App\Http\Controllers\UserController#logout');
});
I am testing it in postman using the route: http://127.0.0.1:8000/api/logout and passing the Bearer token, which I get from the login request, as a value.
It should be POST Request instead of GET request, because your deleting/making change to the database.
The route should look like this:
Route::POST('logout', 'App\Http\Controllers\UserController#logout')->middleware('auth:api');
And the logout method in in UserController should be.
public function logout()
{
auth()->user()->tokens->each(function ($token, $key) {
$token->delete();
});
return response()->json([
'message' => 'Logged out successfully!',
'status_code' => 200
], 200);
}
In your logout function, it should expire the token, not delete it
public function logout(Request $request)
{
$request->user()->token()->revoke();
return response()->json([], Response::HTTP_NO_CONTENT);
}
OR if you wanna expire all his tokens:
use Illuminate\Support\Facades\Auth;
public function logout(Request $request)
{
$userTokens = Auth::user()->tokens();
foreach($userTokens as $token)
{
$token->revoke();
}
}
I wrote an API in Laravel 5.8 for User Login and Register.
I use JWTAuth in Laravel 5.8. When I tested the Login on Postman, it generated an error, undefined variable: token. I tried to write the API for register, when I tested it, it worked perfectly. Based on what I saw online, I tried adding \Illuminate\View\Middleware\ShareErrorsFromSession::class, to the kernel but still the same error.
LoginController
public function login(Request $request)
{
$credentials = $request->json()->all();
try
{
if(! $token == JWTAuth::attempt($credentials))
{
return response()->json(['error' => 'invalid_credentials'], 400);
}
}
catch(JWTException $e)
{
return response()->json(['error' => 'could_not_create_token'], 500);
}
return response()->json(compact('token'));
}
public function register(Request $request)
{
$validator = Validator::make($request->json()->all() , [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6',
'username' => 'required|string|max:255',
]);
if($validator->fails()){
return response()->json($validator->errors()->toJson(), 400);
}
$user = User::create([
'name' => $request->json()->get('name'),
'email' => $request->json()->get('email'),
'password' => Hash::make($request->json()->get('password')),
'username' => $request->json()->get('username'),
]);
$token = JWTAuth::fromUser($user);
return response()->json(compact('user', 'token'), 201);
}
api.php
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::post('register', 'UserController#register');
Route::post('login', 'UserController#login');
Route::get('profile', 'UserController#getAuthenticatedUser');
I expected success, but it gave error:
ErrorException: Undefined variable: token in file C:\xampp\htdocs\laravelapi\app\Http\Controllers\UserController.php on line 52
This is my line 52:
if(! $token == JWTAuth::attempt($credentials))
define $token before line 52
$token = null;
You should use assignment operator and not equal ==:
$token = JWTAuth::attempt($credentials))
Also in the login function you should generate a token from user to return
public function login(Request $request)
{
$credentials = $request->json()->all();
try
{
if(! $token = JWTAuth::attempt($credentials))
{
return response()->json(['error' => 'invalid_credentials'], 400);
} else {
// Generate token from user
$token = JWTAuth::attempt($credentials);
return response()->json(compact('token'));
}
}
catch(JWTException $e)
{
return response()->json(['error' => 'could_not_create_token'], 500);
}
}
I am trying to get info from action, but when click, just page refresh and in console I get code 302 and stay on current page.
I read a lot of similar topics here but found nothing.
I am trying to execute http://laravel2.lo/getUserChannels?user_id=2
Laravel 5.7.16
route:
Auth::routes();
Route::group(['middleware' => ['auth']], function () {
Route::view('createUser', 'createuser');
Route::view('createChannel', 'createchannel');
Route::view('joinChannel', 'joinchannel');
Route::get('profile', 'UserController#profile');
Route::get('users', 'UserController#users');
Route::get('getChannelUsers', 'UserController#getChannelUsers');
Route::get('getUserChannels', 'ChannelController#getUserChannels');
});
ChannelController:
class ChannelController extends Controller
{
public function getUserChannels(Request $request)
{
$this->validate($request, [
'user_id' => 'required|integer',
]);
/** #var User $user */
$user = User::find($request->user_id);
return view('singleuser', ['channels' => $user->channels, 'username' => $user->name]);
}
}
In the log file no errors.
Thanks for any help and advise.
I don't think you'll receive query params as anything other than strings, so your integer validation fails.
To improve your error handling you could customize your App\Exceptions\Handler, catch your ValidationException errors with something like get_class() or instanceOf and do some neat stuff there
And of course you could not use query params at all by using Route::get('getUserChannels/{id}', 'controller#show'); and access it /getUserChannels/2 - then you could probably validate it as an integer
You could go with
Route::get('getUserChannels/{id}', ...
public function getUserChannels($id)
{
$user = User::findOrFail($id);
return view('singleuser', [
'channels' => $user->channels,
'username' => $user->name
]);
}
Then it would just throw a 404 if string, not found etc...
class ChannelController extends Controller
{
public function getUserChannels(Request $request)
{
$validator = \Validator::make($request->all(), ['user_id' => 'required|integer']);
if($validator->fails())
{
$error = $validator->errors()->first();
dd($error);
}
/** #var User $user */
$user = User::find($request->user_id);
return view('singleuser', ['channels' => $user->channels, 'username' => $user->name]);
}
}
When a user logs in I want them to be redirected to their profile page instead of homepage. I have a method in another controller that gets a user profile. Not sure what I need to do since the user profile takes a username variable but when user logs in I'm only asking for email and password.
My route file, but the following method is in a different controller from the authentication controller.
Route::get('/user/{username}', [
'uses' => 'ProfileController#getProfile',
'as' => 'profile.index',
'middleware' => ['auth'],
]);
My following method is in my authentication controller.
public function postSignin(Request $request)
{
$this->validate($request, [
'email' => 'required',
'password' => 'required',
]);
if (!Auth::attempt($request->only(['email', 'password']), $request->has('remember'))) {
return redirect()->back()->with('info' , 'Could not sign you in with that info.');
}
$user= User::where('username', $username)->first();
return redirect()->route('profile.index')
->with('info', 'You are now signed in.')
->with('user', $user);
}
The following is in my profile controller..
public function getProfile($username)
{
$user= User::where('username', $username)->first();
if (!$user){
abort(404);
}
return view('profile.index')
->with('user', $user);
}
To correctly build the route, you need to pass the username here:
$user = User::where('username', $username)->first();
return redirect()->route('profile.index', ['username' => $user->username])
->with('info', 'You are now signed in.')
->with('user', $user);
Get the username from the email provided and pass the $username variable to route:
public function postSignin(Request $request)
{
if (!Auth::attempt($request->only(['email', 'password']),$request->has('remember')))
{
return redirect()->back()->with('info' , 'Could not sign you in with that info.');
}
$username=User::where(['email'=>$request->email])->first()->username;
return redirect()->route('profile.index')->with('username', $username);
}
You can use as like below.
if (!Auth::attempt($request->only(['email', 'password']), $request->has('remember'))) {
return redirect('profile.index')->with('info' , 'Could not sign you in with that info.');
I'm using laravel 5.1 and the modular package.
In my controller I use the following login method:
public function postLogin(Request $request)
{
$email = $request->input('email');
$password = $request->input('password');
if (Auth::attempt(['email' => $email, 'password' => $password])) {
return redirect()->intended('admin/dashboard');
}
return redirect('/login')->withErrors([
'email' => 'These credentials do not match our records.']);
}
My route:
Route::group(array('module' => 'Admin', 'namespace' => 'App\Modules\Admin\Controllers'), function() {
Route::get('admin/dashboard', [
'middleware' => 'auth',
'uses' => 'AdminController#index'
]);
}}
My controller:
public function index()
{
return view("Admin::index");
}
My Middleware/Authenticate:
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('auth/login');
}
}
return $next($request);
}
This works and redirects me to the index view after login.
When the user is not logged in, it is still possible to access the index view by accessing the url: localhost/admin/dashboard.
How can I redirect the user to a custom page which shows an error to the user that it is not possible to access the url localhost/admin/dashboard when he is not logged in?
Any ideas? Thank you
The issue is with your route the middleware should be at the top level as soon as you hit the controller it should redirect if not authenticated
Route::group(['middleware'=>'auth','module' => 'Admin', 'namespace' => 'App\Modules\Admin\Controllers'], function()
{
Route::get('admin/dashboard', ['uses' => 'AdminController#index']);
});
secondly if you want to redirect user to a custom page you can do this
public function redirectUnAuthenticateUser()
{
\Session::flash('login_error', 'Kindly login before you can access this page');
//create a view that user would be redirected to
return view('session.unauthenticated') ;
}
and the change your auth function to below
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->route('you-custom-rout-name-matching-above-function');
}
}
return $next($request);
}
and on your view you can get the value of the flash message