Is there any way that I can allow user to login only from one device?
Thanks in advance
Well, you would need to check at a central place, if there is an already existing session for the user that currently want to log in - and if yes, delete all existing sessions.
The central place would proably be when the login happens or inside an auth middleware.
To delete all existing sessions for the user you can run
DB::table('sessions')->where('user_id', $user->id)->delete();
Log in only from one device, f. ex. Laptop
That is probably not possible as each device would need to send a unique identifier - which it doesn't. As example, your Laptop would need to send a unique identifier to the Laravel system, so that your Laravel application would know, that it is the Laptop the login is coming from.
The login forms normally only takes a username/email and a password, so no unique property to identify your Laptop.
You could probably check for browser user agent or things like this, but that is all fakeable and does not guarantee a 100% proof identification of the device.
You can use deviceInspect middleware and check user agent (it could be fake as #codedge said) and use it after auth middleware
As you can see the user will be authenticated but routes will be protected by device
Create middleware
class DeviceInspect
{
public function handle($request, Closure $next)
{
$user = Auth::user(); //or $request->user()
// TODO get enabled device/s from datebase for $user - by userId
$enabledDevice = "Dalvik/2.2.0 (Linux; U; Android 10.0.1; AM-A89R Build/NMB55D)"; //example
$currentDevice = $request->userAgent(); //or $_SERVER['HTTP_USER_AGENT'];
//it could be fake like codedge said
if ($enabledDevice !== $currentDevice) {
$data = array(
"device" => false,
"message" => "your message to user",
);
return response([$data], 401); // or something else
}
return $next($request);
}
}
add this to App\Http\Kernel
protected $routeMiddleware = [
...
'device' => 'App\Http\Middleware\DeviceInspect',
];
and use it like below
//in controller
class SomeController extends Controller {
public function __construct() {
parent::__construct();
$this->middleware(['auth', "device"]);
}
}
or
//Or in routes
Route::get('/profil', function () {
//
})->middleware(['auth', 'device']);
or
Route::group(['prefix' => '/v1/data', 'namespace' => 'Api\V1', 'as' => 'api.', 'middleware' => ['auth:api', 'device']], function () {
Route::resource('activity', 'Data\DataController', ['only' => ['index', 'show']]);
});
Related
I'm using Laravel 5.3 and want to return the user to a user-specified URL after login.
I am using a lot of JavaScript and want to return to a specific URL, that isn't the URL the user is trying to access, after they have logged in. The URL is different depending on user action.
For example:
/login?r=/come/here/after/login
I can pass this URL to the login screen, but I can't find a way to pass it through to the auth controller for redirection after login is successful.
In your case I would create a custom auth middleware just for the custom redirected routes:
class PostLoginRedirect
{
public function handle($request, Closure $next, $guard = null)
{
$response = $next($request);
if (\Auth::id() && isset($request->r)) {
// Return the new route redirect.
return redirect($request->r);
}
// Return the custom one in case r? don't exists.
return $response;
}
}
Declare your new middleware on app/Http/Kernel.php
protected $routeMiddleware = [
'login-redirect' => \YourNamespace\PostLoginRedirect::class
];
And add to your routes:
$this->post('login', ['middleware' => 'login-redirect', 'uses' => 'Auth\AuthController#login']);
Maybe you need to do a minor change but must work :)
How am I able to maintain or create a session through Ajax login. I have a Laravel installation not that much different from a basic make:auth installation.
I had to ovewrite some parts of the authcontroller to return json instead of redirects. Here's the login part:
/**
* Handle an authentication attempt.
*
* #return Response
*/
public function login(Request $request)
{
$this->validate($request, [
$this->loginUsername() => 'required',
'password' => 'required'
]);
// 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.
$throttles = $this->isUsingThrottlesLoginsTrait();
if ($throttles && $this->hasTooManyLoginAttempts($request)) {
// to many attempts
if ( $request->ajax() )
{
$this->response['code'] = 406;
$this->response['message'] = $this->sendLockoutResponse($request);
return response()->json($this->response);
}
return $this->sendLockoutResponse($request);
}
$credentials = $this->getCredentials($request);
$credentials['is_active'] = 1;
if (Auth::attempt($credentials, $request->has('remember'))) {
// succes
return $this->handleUserWasAuthenticated($request, $throttles);
}
// 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.
if ($throttles) {
$this->incrementLoginAttempts($request);
}
// error
if ( $request->ajax() )
{
$this->response['code'] = 406;
$this->response['message'] = $this->getFailedLoginMessage();
return response()->json($this->response);
}
return redirect()->back()
->withInput($request->only($this->loginUsername(), 'remember'))
->withErrors([
$this->loginUsername() => $this->getFailedLoginMessage()
]);
}
/**
* Handle an authenticated response.
*
* #return Response
*/
public function authenticated($request, $user)
{
if ( $request->ajax() )
{
$this->response['message'] = "success";
return response()->json($this->response);
}
else
{
return redirect()->intended($this->redirectPath());
}
}
Here are the routes used:
Route::group(['namespace' => 'Auth'], function() {
Route::post('/login', ['uses' => 'AuthController#login', 'as' => 'login']);
Route::post('/registreer', ['uses' => 'AuthController#postRegister', 'as' => 'register']);
Route::post('/reset', ['uses' => 'PasswordController#sendResetLinkEmail', 'as' => 'reset']);
});
I am working with Vue.js in the frontend which get the error and succes responses perfectly. Only after refreshing the browser i am not in a logged in state. How am I able to do this.
There's no session when you are working with AJAX / JSON REST APIs. Instead of sessions, REST APIs use tokens / some kind of authentication.
If you are building a REST API and using VueJS as the front end framework for a single page application, use the api middleware instead of the default web middleware.
Read more information about JSON Web Tokens here:
https://jwt.io/introduction/
You are basically creating a stateless application when you are using Ajax. The frontend side basically didnt need to know the state of the user, wether he is already login or not. So you didnt need any session.
What you need to do is get information from the server wether your user is authorized to get any resource on the server. This is basically Authenticating (the process to validate user credential that being sent to the server and then returning sort of id to the user) and Authorization the process to check wether the id is authorized to access the resource requested.
I guess i declared my question not properly because of the misunderstandings. However i did get it to work. The fix is to put middleware around the specific routes. Now I am to login trough a Ajax request.
Route::group(['middleware' => 'web'], function () {
...
});
This is my first attempt at a laravel package and have run into an issue where Auth::attempt($credentials) works within my login controller, but upon redirection to a protected route or controller, the user is no longer authenticated. Below is my login controller method with the redirect to dashboard commented out.
public function attempt(Request $request){
$email = strtolower(strip_tags(htmlspecialchars($request->input('email'))));
$password = strip_tags(htmlspecialchars($request->input('password')));
if (Auth::attempt(array('email' => $email, 'password' => $password)))
{
// Redirect to dashboard route
//return redirect()->intended('/admin');
if(Auth::check())
print_r(Auth::user());
}
}
A response to valid credentials prints out the correct user record and Auth::check returns true. But, when redirected to the admin controller, the user is not authenticated. Below is the admin controller method that should output the authenticated user, but only returns "not logged".
public function index()
{
if(Auth::check()) print_r(Auth::user());
else echo "not logged";
}
Both controllers use Auth;, their namespaces are consistent with vendor/package/pathToDir, db is setup correctly, and the encryption key has been set. Any ideas on what's going wrong? Thanks
Turns out the issue was with the new web middleware, moved all my routes that require session data in to the route group and everything works as normal.
Route::group(['middleware' => ['web']], function () {
Route::get("/login", ['uses'=>'SiteLogin#index']);
Route::post("/login", ['uses'=>'SiteLogin#attempt']);
Route::get("/logout", ['uses'=>'SiteLogin#logout']);
Route::group(['prefix' => 'admin', 'middleware' => 'auth'], function () {
Route::get('/', ['uses'=>'Admin#index']);
});
});
The default behavior of the method attempt is to not keep the user logged.
You should change it to:
if (Auth::attempt(array('email' => $email, 'password' => $password), false, true))
This way you will set remember as false and login as true.
Check more about this here: https://laravel.com/docs/5.2/authentication
I have a small Lumen / Laravel app that is just used as an API. I am able to sign in and set JWT tokens but after a period of time they timeout, I was expecting them to refresh each time an Endpoint was hit.
I've been looking at the docs for Tymon's JWT-AUTH but I cannot seem to get it to work.
Below is an example of one of my end points which return an array of all the users in the db. But when the token timesout the endpoint returns the error You don't have previleges to view all users
I'd be very grateful if someone was able to advise me or show me how to make my code refresh a token when someone is hitting an endpoint.
Inside Controller
public function index(Request $request)
{
$user = JWTAuth::parseToken()->authenticate();
if (!$user->isAdmin()) {
return $this->error_respond(['error' => "You don't have previleges to view all users"]);
}
$users = $this->repository->findAllWithPlan();
return $this->respond(['users' => $users]);
}
Inside Routes.php
$app->group(['middleware' => 'jwt.auth'], function ($app) {
/**
* Show All users
*/
$app->get(
'users',
[
'as' => 'user.all',
'middleware' => 'cors',
'uses' => 'App\Http\Controllers\UserController#index'
]
);
});
I've started learning Laravel 5.1 and so far I'm liking it! But there is one thing I don't get yet..
In my previous project I had 2 specific controllers (eg: "normal", "extended") which , after a successfull login, were called based on the Users user_group from the database.
If "Foo.Bar" enters his valid credentials and has the group normal he is redirected to NormalControler. Since I wasn't using any framework I restricted access to the other group by setting a $_SESSION with the group and checking it. So if another group tried to access that controller he got redirected.
How would this be achievable in Laravel 5? So far I have a controller which is callable without an Authentication and one restricted by this code in routes.php :
// All routes in the group are protected, only authed user are allowed to access them
Route::group(array('before' => 'auth'), function() {
// TO-DO : Seperate Controller access
});
And the login looks like this :
public function performLogin()
{
$logindata = array(
'username' => Input::get('user_name'),
'password' => Input::get('user_pass')
);
if( Auth::attempt( $logindata ) ){
// return \Redirect::to( check group and access this controller based on it);
}
else {
// TO-DO : Redirect back and show error message
dd('Login failed!');
}
}
----- EDIT -----
I've run the artisan command and made this middleware as you suggested :
namespace App\Http\Middleware;
use Closure;
use Request;
class GroupPermissions
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next, $group)
{
// Check User Group Permissions
if( $request->user()->group === $group ){
// Continue the request
return $next($request);
}
// Redirect
return redirect('restricted');
}
}
and edited this line into Kernel.php into $routeMiddleware :
'group.perm' => \App\Http\Middleware\GroupPermissions::class
I think this is done right so far, correct me if I'm wrong! Could I then do something like this to restrict the controllers?
Route::group(array('before' => 'auth'), function() {
Route::group( ['middleware' => 'group.perm', 'group' => 'normal'], function(){
Route::get('/normal/index', 'DummyNormalController#index');
});
Route::group( ['middleware' => 'group.perm', 'group' => 'extended'], function(){
Route::get('/extended/index', 'DummyExtendedController#index');
});
});
Ok, here is what you might do. Once user is logged in, you would check his credentials, get his user_group and decide what controller he should be redirected to.
if( Auth::attempt( $logindata ) ){
$user = Auth::user();
if ($user->inGroup('normal')) {
return redirect()->route('normal_controllers_named_route');
}
return redirect()->route('extended_controllers_named_route');
}
return redirect()->back()->withFlashMessage('don\'t get me wrong');
This will handle right routing after logging in.
The next portion where you need to protect you routes from unwanted user groups may be achieved with middlewares.
do an artisan command php artisan make:middleware ShouldBeInGroup
go to app/http/Kernel.php and add your new middleware to the routeMiddleware array. Key of the item might be anything you like. Let's call in inGroup. So: 'inGroup' => 'App\Http\Middleware\ShouldBeInGroup'
Now, in your controller, in constructor, you are able to call this middleware
$this->middleware('inGroup:extended'); //we also passing the name of the group
at lastly, work on the our middleware. Open newly created ShouldBeInGroup class and edit the handle method.
public function handle($request, Closure $next, $groupName)
{
if (Auth::check() && Auth::user()->inGroup($groupName)) {
return $next($request);
}
return redirect('/');
}
And finally you should work on inGroup method, that should return true of false. I assume that you have user_group field your users table. Then in your User eloquent model add the method
public function inGroup($groupName) {
return $this->user_group == $groupName;
}
Edit
if you want to use this middleware in your routes, you can do the following
Route::group(array('before' => 'auth'), function() {
Route::get('/normal/index', ['middleware' => 'group.perm:normal', 'uses' =>'DummyNormalController#index']);
}
But generally it's better to put all your middlewares into your Controller's constructor
public function __construct(){
$this->middleware('group.perm:normal'); // you can also pass in second argument to limit the methods this middleware is applied to : ['only' => ['store', 'update']];
}
And also on this note, Laravel provides built in auth middleware that you can use
public function __construct(){
$this->middleware('auth');
$this->middleware('group.perm:normal');
}
so then your routes would become much cleaner, just:
Route::get('normal/index', 'DummyNormalController#index');
I think the best way to do that is using middlewares. See the doc here
You can easily create a middleware using the following artisan command:
php artisan make:middleware ExtendedMiddleware
If you can't or don't want to use artisan, you need to create a class in The App/Http/Middleware folder.
In this class you'll need the following method to handle the request. In the method you can check for the user group.
public function handle($request, Closure $next)
{
// check user group
if( user_group_ok )
return $next($request); // Continue the request
return redirect('restricted'); // Redidrect
}
You can then use this middleware in your route.php file:
Route::group(['middleware' => 'auth'], function()
{
// Logged-in user with the extended group
Route::group(['middleware' => 'extended'], function()
{
// Restricted routes here
});
// Normal routes here
});
You can create a Middleware called : PermissionFilter
In PermissionFilter, you check if requesting user is in the group or not.
I can't provide a demo for now, but if you want I can make a demo later.
L5 middleware: http://laravel.com/docs/5.1/middleware