I need to force all routes with SSL in Lumen 5.6.
For examples http://www.mywebsite.com to https://www.mywebsite.com
I tried many different solutions on the web, but nothing worked for me:
Middelware, .htaccess, AppServiceProvider
Which the best way to force SSL scheme in Lumen 5.6?
You can create a middleware class and use the redirect()->to function with the secure parameter set to true.
To achieve this, create a class (HttpsProtocol.php) and place it in the middleware directory:
namespace App\Http\Middleware;
use Closure;
class HttpsProtocol{
/**
* #param \Illuminate\Http\Request $request
* #param Closure $next
*
* #return \Illuminate\Http\Response|\Laravel\Lumen\Http\ResponseFactory|mixed
*/
public function handle($request, Closure $next) {
if (!$request->secure() && app()->environment() === 'production') {
return redirect()->to($request->getRequestUri(), 302, [], true);
}
return $next($request);
}
}
And add the middleware to your $app->middleware array found in app.php.
$app->middleware([
App\Http\Middleware\HttpsProtocol::class
]);
Related
Assume the following simple web app:
<?php
// src/App/App.php
namespace Practice\Sources\App;
use Closure;
use Laminas\Diactoros\ServerRequestFactory;
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\RequestHandlerInterface;
class App implements RequestHandlerInterface
{
private Closure $requestProvider;
private ResponseFactoryInterface $responseFactory;
private SapiEmitter $responseEmitter;
public function __construct(ResponseFactoryInterface $responseFactory)
{
$this->requestProvider = fn() => ServerRequestFactory::fromGlobals();
$this->responseFactory = $responseFactory;
$this->responseEmitter = new SapiEmitter();
}
public function run(): void
{
$request = ($this->requestProvider)();
$response = $this->handle($request);
$this->responseEmitter->emit($response);
}
public function handle(RequestInterface $request): ResponseInterface
{
$response = $this->responseFactory->createResponse();
$response->getBody()->write('hello world');
return $response;
}
}
One can easily run it by placing the following code in their web front-controller (e.g. public_html/index.php):
<?php
// web-root/front-controller.php
use Laminas\Diactoros\ResponseFactory;
use Practice\Sources\App\App;
require_once __DIR__.'/../vendor/autoload.php';
$responseFactory = new ResponseFactory();
$app = new App($responseFactory);
$app->run();
Now, I'd like to run Codeception feature tests against it, written in Gherkin. Consider the following simple test:
# tests/Feature/run.feature
# (also symlink'ed from tests/Codeception/tests/acceptance/ )
Feature: run app
Scenario: I run the app
When I am on page '/'
Then I see 'hello world'
To run acceptance tests against it, I have to provide my steps implementation. I'll reuse standard steps for that, provided by the Codeception:
<?php
// tests/Codeception/tests/_support/FeatureTester.php
namespace Practice\Tests\Codeception;
use Codeception\Actor;
abstract class FeatureTester extends Actor
{
// use _generated\AcceptanceTesterActions;
// use _generated\FunctionalTesterActions;
/**
* #When /^I am on page \'([^\']*)\'$/
*/
public function iAmOnPage($page)
{
$this->amOnPage($page);
}
/**
* #Then /^I see \'([^\']*)\'$/
*/
public function iSee($what)
{
$this->see($what);
}
}
<?php
// tests/Codeception/tests/_support/AcceptanceTester.php
namespace Practice\Tests\Codeception;
class AcceptanceTester extends FeatureTester
{
use _generated\AcceptanceTesterActions;
}
# tests/Codeception/codeception.yml
namespace: Practice\Tests\Codeception
paths:
tests: tests
output: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
actor_suffix: Tester
extensions:
enabled:
- Codeception\Extension\RunFailed
# tests/Codeception/tests/acceptance.suite.yml
actor: AcceptanceTester
modules:
enabled:
- PhpBrowser:
url: http://practice.local
gherkin:
contexts:
default:
- \Practice\Tests\Codeception\AcceptanceTester
But now, I want to use same tests code to run these same tests as functional tests using Codeception. For this, I have to enable the module that implements these same steps in functional way. Which one do I use? Codeception provides several, but they're for 3rd party frameworks, e.g. Laravel, Yii2, Symphony etc. What do I do for such a simple app that doesn't use any 3rd party framework?
Here's what I've managed to do. I've created my own \Codeception\Lib\InnerBrowser implementation that inherits from \Codeception\Module\PhpBrowser provided by Codeception, in which I substitute the web client that Codeception uses (it uses Guzzle) with my own implementation (which also inherits from the Guzzle client) that doesn't perform any web requests but requests my app instead:
# tests/Codeception/tests/functional.suite.yml
actor: FunctionalTester
modules:
enabled:
- \Practice\Tests\Codeception\Helper\CustomInnerBrowser:
url: http://practice.local
gherkin:
contexts:
default:
- \Practice\Tests\Codeception\FunctionalTester
<?php
// tests/Codeception/tests/_support/FunctionalTester.php
namespace Practice\Tests\Codeception;
class FunctionalTester extends FeatureTester
{
use _generated\FunctionalTesterActions;
}
In order for this to work, I have to make my app return Guzzle Responses (which implement PSR's ResponseInterface as well) - because PhpBrowser expects its web client to return them - which is why I had to make the ResponseFactory a constructor parameter to be able to substitute it in tests.
<?php
// tests/Codeception/tests/_support/Helper/CustomInnerBrowser.php
namespace Practice\Tests\Codeception\Helper;
use Codeception\Module\PhpBrowser;
use Http\Factory\Guzzle\ResponseFactory;
use Practice\Sources\App\App;
class CustomInnerBrowser extends PhpBrowser
{
private App $app;
public function __construct(...$args)
{
parent::__construct(...$args);
$responseFactory = new ResponseFactory();
$this->app = new App($responseFactory);
}
public function _prepareSession(): void
{
parent::_prepareSession();
$this->guzzle = new CustomInnerBrowserClient($this->guzzle->getConfig(), $this->app);
$this->client->setClient($this->guzzle);
}
}
<?php
// tests/Codeception/tests/_support/Helper/CustomInnerBrowserClient.php
namespace Practice\Tests\Codeception\Helper;
use GuzzleHttp\Client as GuzzleClient;
use Practice\Sources\App\App;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
class CustomInnerBrowserClient extends GuzzleClient
{
private App $app;
public function __construct(array $config, App $app)
{
parent::__construct($config);
$this->app = $app;
}
public function send(RequestInterface $request, array $options = []): ResponseInterface
{
return $this->app->handle($request);
}
}
In such a configuration, everything seems to work fine.
But there's a problem. Notice the App::handle() signature:
public function handle(RequestInterface $request): ResponseInterface
- it differs from the one that it implements, which is declared in RequestHandlerInterface:
public function handle(ServerRequestInterface $request): ResponseInterface;
Technically, it's completely legal because it doesn't break the parameter contravariance required by the Liskov Substitution Principle.
The problem that I've faced is that PhpBrowser assumes that it sends a (client-side) RequestInterfaces (over the network) but my app requires a (server-side) ServerRequestInterface instead, to be able to access parameters that are set on the server side such as ServerRequestInterface::getParsedBody(), session etc.
How do I workaround this? Framework modules provided by Codeception already do this somehow... And BTW, haven't Codeception (or someone else) provided yet an easy way to run functional tests against custom code?
Here's composer.json BTW:
{
"require": {
"php": "~7.4",
"laminas/laminas-diactoros": "^2.5",
"laminas/laminas-httphandlerrunner": "^1.3"
},
"require-dev": {
"codeception/codeception": "^4.1",
"codeception/module-phpbrowser": "^1.0.0",
"http-interop/http-factory-guzzle": "^1.0"
},
"autoload": {
"psr-4": {
"Practice\\Sources\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Practice\\Tests\\Unit\\": "tests/Unit/",
"Practice\\Tests\\Support\\": "tests/Support/",
"Practice\\Tests\\Codeception\\": "tests/Codeception/tests/_support/",
"Practice\\Tests\\Codeception\\_generated\\": "tests/Codeception/tests/_support/_generated/",
"Practice\\Tests\\Codeception\\Helper\\": "tests/Codeception/tests/_support/Helper/"
}
},
"scripts": {
"test-feature": "codecept run --config tests/Codeception/codeception.yml"
}
}
I am trying to login and logout from a create-react-app application which uses an application with Laravel 7.x as backend. Where can I put the custom response message for /login and /logout auth routes in Laravel 7.x. I used the artisan command for auth scaffolding.
I know about Single Page Application authentication in Laravel. It is given in the Laravel Sanctum page. https://laravel.com/docs/7.x/sanctum. I have followed everything there and have no problems with that.
I get redirected to /home route even when I have commented out the line in LoginController.php
protected $redirectTo = RouteServiceProvider::HOME;
I tried to look up the documentation https://laravel.com/docs/7.x/authentication it says "Laravel provides an empty authenticated(Request $request, $user) method that may be overwritten if desired:". But don't know where this method can be written.
So I will answer my own question. This method is present in the trait AuthenticatesUsers.php which is present in vendor/laravel/ui/auth-backend/ directory.
I added this in the empty method called authenticated() in AuthenticateUsers.php trait present in above link.
/**
* The user has been authenticated.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function authenticated(Request $request, $user)
{
return new Response(['success' => 'you have been authenticated'], 200);
}
For custom logout response, use the loggedOut() method in AuthenticatesUsers.php trait.
Hope this helps someone. I also created a pull request in the docs repository, hope it gets accepted. Thanks.
I'm using Laravel 6. I want to generate a new API token for the user each time the user logged in.
Referring to some answers on StackOverflow, there is a method authenticated in LoginController which is been called just after the user is logged in successfully. I cannot find the authenticated method in Laravel 6.
Is there a new way to achieve the same thing in Laravel 6?
As per Laravel Documentation:
If you need more robust customization of the response returned when a
user is authenticated, Laravel provides an empty authenticated(Request
$request, $user) method that may be overwritten if desired:
/**
* The user has been authenticated.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function authenticated(Request $request, $user)
{
return response([
//
]);
}
Just place the following method inside app\Http\Controllers\LoginController (overriding it):
use Illuminate\Http\Request;
protected function authenticated(Request $request, $user)
{
// stuff to do after user logs in
return redirect()->intended($this->redirectPath());
}
Reference:
Laravel -> Authentication -> Authenticating
I just upgraded my application from Laravel 5.4 to v 5.5. Non authenticated users are not redirecting properly now.
Normally a non authenticated user should be redirected to /manage/login but it is redirected to /login route.
Everything was working perfect in Laravel v 5.4
My app contain two guards.
Routing in web.php
Auth::routes();
Route::middleware(['auth:manager'])->group(function () {
Route::get('/manage', 'Manage\AdminController#dashboard')->name('manage.home');
});
So before upgrade a non authenticated user trying to access /manage was redirected to /manage/login but after upgrading it is redirecting to /login.
I have Auth Controllers copied and modified as needed in Manage\Auth.
Similarly Views are in folder structure Manage\Auth.
My LoginController in Controllers\Manage\Auth
|
Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/manage/';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function showLoginForm()
{
return view('manage.auth.login');
}
public function logout(Request $request)
{
$this->guard()->logout();
$request->session()->flush();
$request->session()->regenerate();
return redirect('/manage');
}
protected function guard()
{
return Auth::guard('manager');
}
I faced the same problem, and it's quit simple to solve.
the point is that if you are using guards you were probably handling unauthenticated exception in your app/Exceptions/Handler.php . when using laravel 5.4 .
After update to 5.5 this is done under vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php .
You should refer to this Laravel 5.5 change unauthenticated login redirect url for more details about how to solve it.
I want to create an API with Laravel 5.3 but i don't need any kind of authentication. Is it possible to get rid of it? I don't want any token or any kind of authentication.
Yes, it's possible
normally in your
route/api.php
you'd have something like
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
you just need to remove the part of the middleware that's referencing auth.
So the above would look like:
Route::middleware('api')->get('/user', function (Request $request) {
return $request->user();
//middleware('api') URI prefix. which would become '/api/user'
});
or
Route::apiResource('user', 'UserController');
//same as above but includes crud methods excluding 'create and edit'
To help anyone in my situation who arrive here : be aware that any route in api.php is prefixed by "api/".
It is set in /app/Providers/RouteServiceProvider.php.
So :
Route::get('/delegates', "APIController#delegate");
Will be accessible from
http://www.yourdomain.com/api/delegates
Sorry if it's a bit off-topic, but hope it can help someone.
Of course you can get rid of it. Just setup your routes to don't use any middleware.
Create your API routes on routes/api.php file, then modify the app/Http/Kernel.php file to set your middlewares correctly:
Remove (or add) the middlewares you don't want on api middleware group.
By default, L5.3 comes with two middlewares on api group:
'api' => [
'throttle:60,1',
'bindings',
],
The first one provides a rate limiting to your API (60 requests/minute),
the second substitutes your model bindings.
It's possible, just create route to your controller and return data (Without any auth middleware).
Allow your route to run without auth
Http\Middleware\VerifyCsrfToken
public function handle($request, Closure $next)
{
if (!$request->is('api/*'))
{
return parent::handle($request, $next);
}
return $next($request);
}
Set route like this
'api' => 'APIController'
This is method in APIController ('/api/data')
public function getData(Request $request)
{
return "Hello";
}