Laravel 5 came out with a nice Auth scaffolding, which included all of the routes/controllers/views for registering and authenticating a users. But I started using Laravel 5.1 recently, and noticed authentication is no longer built in. How can I add it back?
Laravel does already have documentation on building authentication into your Laravel 5.1 app. However, I'll go through this in a bit more detail...
Installing Laravel
First, make sure you have a fresh install of Laravel. Here is my tutorial on Installing Laravel 5.1 on OSX with MAMP.
Add Twitter Bootstrap
After downloading bootstrap add the bootstrap.css file into the public/css directory. (you may have to create the css directory.
Also copy over bootstrap's fonts directory into your app's public directory.
Add Authentication Routes
Add the following routes to the app/Http/routes.php file.
// Authentication routes...
Route::get('auth/login', 'Auth\AuthController#getLogin');
Route::post('auth/login', 'Auth\AuthController#postLogin');
Route::get('auth/logout', 'Auth\AuthController#getLogout');
// Registration routes...
Route::get('auth/register', 'Auth\AuthController#getRegister');
Route::post('auth/register', 'Auth\AuthController#postRegister');
// Password reset link request routes...
Route::get('password/email', 'Auth\PasswordController#getEmail');
Route::post('password/email', 'Auth\PasswordController#postEmail');
// Password reset routes...
Route::get('password/reset/{token}', 'Auth\PasswordController#getReset');
Route::post('password/reset', 'Auth\PasswordController#postReset');
Add Authentication Views
First let's create a blade template to use for all of our other views. We can do that by creating a resources/views/auth/app.blade.php file. And copy/paste the code shown here: https://github.com/laravel/laravel/blob/5.0/resources/views/app.blade.php
Create a new resources/views/auth directory. Within that directory, create the following files.
login.blade.php (https://github.com/laravel/laravel/blob/5.0/resources/views/auth/login.blade.php)
password.blade.php (https://github.com/laravel/laravel/blob/5.0/resources/views/auth/password.blade.php)
register.blade.php (https://github.com/laravel/laravel/blob/5.0/resources/views/auth/register.blade.php)
reset.blade.php (https://github.com/laravel/laravel/blob/5.0/resources/views/auth/reset.blade.php)
For the "forgot password" email, create a resources/views/emails directory, and place the following file into it.
password.blade.php (https://github.com/laravel/laravel/blob/5.0/resources/views/emails/password.blade.php)
Create Database & Tables
To make it so that we can actually register a new user and login, we'll have to create the proper database tables. Fortunately, this is already available through migrations.
First, create a new database table, and define it's connection in the .env file.
DB_HOST=localhost
DB_DATABASE=name
DB_USERNAME=root
DB_PASSWORD=xxxxxxx
The trigger the migration with the following command:
php artisan migrate
Since I'm using MAMP, I got this error when trying to migrate.
[PDOException]
SQLSTATE[HY000] [2002] No such file or directory
Solution was to add the unix_socket key with a value of the path that the mysql.sock resides in MAMP.
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
'unix_socket' => '/Applications/MAMP/tmp/mysql/mysql.sock',
],
Setup SMTP Server
Laravel 5.1 defaults to mailtrap.io. First time I gave this a try, and it's actually quite easy! First step is to setup mailtrap.io account.
Update .env file with SMTP settings (provided after signing up)
MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=xxxxxx
MAIL_PASSWORD=xxxxxxx
MAIL_ENCRYPTION=null
Update from address in config/mail.php file.
'from' => ['address' => 'noreply#test.com', 'name' => 'test'],
Create Dashboard
Add dashboard routes
Route::get('dashboard', 'Dash\DashboardController#home');
Add dashboard controllers to app/Http/Controllers/Dash/DashboardController.php
<?php
namespace App\Http\Dash\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class DashboardController extends Controller
{
public function home(Request $request)
{
return view('dashboard/home');
}
}
Note the use of use App\Http\Controllers\Controller;. This is important since were using a different namespace for our dashboard.
And the view at resources/views/dashboard/home.blade.php:
#extends('app')
#section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">Dashboard</div>
<div class="panel-body">
You are logged in!
</div>
</div>
</div>
</div>
</div>
#endsection
Update login redirects:
Update app/Http/Middleware/RedirectIfAuthenticated
with:
return redirect('/dashboard');
Add to Auth/PasswordController.php and Auth/AuthController.php files.
protected $redirectTo = '/dashboard';
Authenticate Dashboard
To restrict access to the dashboard to only those that are logged in, we can ddd the following to the Dashboard controller
public function __construct()
{
$this->middleware('auth');
}
Aside from the docs as pointed by Marty Thomas you can also try to use this package for auth scaffolding.
Related
Can anybody give me a helping push to get my hosted Blazor application (Client, Server and Shared) to request a login immediately, before the application is initially shown. I want the experience that a user must log in before accessing the application at all.
My starting point is the Blazor Webassembly (hosted) template with Api Authorization (Individual User Accounts)
Using the Authorize attribute on either server-side actions or a client-side Razor page will not initiate the authentication flow before the specific action/page with the Authorize attribute is being requested by the user. How would I go about having the authorization flow kicked off as the first thing, before the application is even displayed for the first time?
I am sure this is possible and even trivial for somebody more savvy than me. Can anybody give me a shove in the right direction, please?
I created a control RedirectToLogin.razor
#inject NavigationManager Navigation
#code {
protected override void OnInitialized()
{
String thisPage = Navigation.Uri.Replace(Navigation.BaseUri, "~/");
Navigation.NavigateTo($"Identity/Account/Login?returnUrl={thisPage}");
base.OnInitialized();
}
}
And then inserted it into the mainlayout.razor
<div class="container-fluid">
<AuthorizeView>
<Authorized>
<NavigationLogger />
<ContextMenuMouseClick>
<MenuTopBar />
<NavMenu />
<SubPageContainer>
#Body
</SubPageContainer>
</ContextMenuMouseClick>
</Authorized>
<NotAuthorized>
<RedirectToLogin />
</NotAuthorized>
</AuthorizeView>
</div>
So when the layout is loaded and it is in the NotAuthorized state it will redirect to the login page and after authorising will return to the page it was trying to access.
Hope this helps.
The Blazor Client is bootstrapped from a static index.html in the wwwroot. In the Server project this is mapped to an Endpoint in the Startup.cs, basically a catch-all to all endpoints not taken by your Razor Pages or Controllers:
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
For your scenario:
Create a new layout in Server, say _LayoutBlazor.cshtml
Re-create the contents of the index.html from the Client. Note that the _framework files from the Client are copied to the Server wwwroot upon build:
:
<app>Loading...</app>
<script src="#Href("~/_framework/blazor.webassembly.js")"></script>
Create a new Razor page and put the "Authorize" tag on it and use the _LayoutBlazor.
Remove the endpoints.MapFallbackToFile("index.html"); from Startup.cs
Mark Gould has created a proof of concept here: RazorBlazor
for my application i want to write an "admin" plugin, named "db" with own auth-component. To manage acl i tried to implement ivanamat/cakephp3-aclmanager as part of my admin tool, because my app won't need user authentification, maybe later.
i load AclManager in plugins/db/Plugin.php
public function bootstrap(PluginApplicationInterface $app)
{
Configure::write('AclManager.aros', array('DbGroups', 'DbRoles', 'DbUsers'));
parent::bootstrap($app);
$app->addPlugin('AclManager', ['routes' => false]);
}
I set up Routing Rules in db/config/routes.php
Router::connect(
'db/acl',
['plugin' => 'AclManager', 'controller' => 'Acl', 'action' => 'index']
);
Router::connect(
'db/acl/:action/*',
['plugin' => 'AclManager', 'controller' => 'Acl']
);
And i set up Auth Configuration in plugins/db/Controller/AppController.php
It's loaded and aside a "Auth not found"-error it works, but this is my problem.
When i debug $this->Auth in app.local/db/ it's filled. But not when i debug in app.local/db/acl. even when i load this plugin in my plugin, it's using Base AppController, not Plugin AppController.
Is it possible to inherit auth from plugin to plugin or load plugins with parent-child-association?
You cannot change what a (controller) class inherits, that is compile time information, and once it's processed, it is what it is, the controller classes of the AclManager plugin do extend App\AppController.
There's lots of different ways to solve your problem, one would for example be to dynamically configure the authentication in your application's base App\AppController class, rather than in your Db plugin's Db\AppController class.
You can check the routing information whether it's a request for the Db plugin or the AclManager plugin, and only load the auth component in that case, something like this:
public function initialize()
{
if (in_array($this->request->getParam('plugin'), ['Db', 'AclManager'], true)) {
$this->loadComponent('Auth', [
// ...
]);
}
}
That way the Db and AclManager plugin controller classes will inherit the authenticaton setup while your main application and possible other plugins are being excluded.
ps. if you're just starting to implement authentication, then I'd strongly suggest that you try the new authentication and authorization plugins, they're much more versatile than the (deprecated) auth component!
I want to use the Authentication plugin for CakePHP 3.8 and I'm having problems that are not in documentation.
After follow Getting Started (https://book.cakephp.org/authentication/1/en/index.html) I have one question.
Originally $fields were specified to change username and password relation in real database, same that Auth component, and login URL is where login form si loaded.
First, in getting started or any part of documentation doesn't says about a login view (form), so, like old Auth Component I created this to Users/login.ctp
<div class="users form">
<?= $this->Flash->render('auth') ?>
<?= $this->Form->create() ?>
<fieldset>
<legend><?= __('Please enter your email and password') ?></legend>
<?= $this->Form->input('email') ?>
<?= $this->Form->input('password') ?>
</fieldset>
<?= $this->Form->button(__('Login')); ?>
<?= $this->Form->end() ?>
</div>
My code in Application.php includes this (with its respective uses and implements):
public function getAuthenticationService(ServerRequestInterface $request, ResponseInterface $response)
{
$service = new AuthenticationService();
$fields = [
'username' => 'email',
'password' => 'password'
];
// Load identifiers
$service->loadIdentifier('Authentication.Password', compact('fields'));
// Load the authenticators, you want session first
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => '/users/login'
]);
return $service;
}
But when I try to login, I have this error, after var_dump in login.ctp I get this:
object(Authentication\Authenticator\Result)[124]
protected '_status' => string 'FAILURE_OTHER' (length=13)
protected '_data' => null
protected '_errors' =>
array (size=1)
0 => string 'Login URL `http://localhost/users/login` did not match `/users/login`.' (length=70)
If I comment 'loginUrl' => '/users/login' line, then login works fine.
Additional notes:
- I've tested with hashed and textplane passwords, same results.
- I've added $this->Authentication->allowUnauthenticated(['view', 'index', 'login', 'add']); in beforeFilter to access login.
- It's a clean cakephp 3.8 install, only database is the same for tests.
- I've added Crud only with cake console.
I would like to learn more about that loginURL, I should include some uses in UsersController? What causes this error?
Thank you
The error messages is currently a little misleading, as it doesn't show you the possible base directory, which is the actual issue that you are experiencing. I've proposed a fix for that, which may make into the next release.
When your application lives in a subdirectory, you need to make sure that your login URL configuration takes that into account, that is by either passing the URL including the base directory, which you could do either manually:
'loginUrl' => '/myapp/users/login'
or by using the router:
'loginUrl' => \Cake\Routing\Router::url('/users/login')
'loginUrl' => \Cake\Routing\Router::url([
'plugin' => null,
'prefix' => null,
'controller' => 'Users',
'action' => 'login'
])
Another option would be to use the routes based URL checker, which can be configured via the form authenticators urlChecker option, then you can define the login URL using URL arrays, without having to use the router:
'urlChecker' => 'Authentication.CakeRouter',
'loginUrl' => [
'plugin' => null,
'prefix' => null,
'controller' => 'Users',
'action' => 'login'
]
See also:
Authentication Cookbook > Authenticators > Form
Authentication Cookbook > URL Checkers
I am using basic template but have adapted the advanced user password reset functionality, for some reason I can't get it to find the mail layouts.
So in \mail\layouts I have
- passwordResetToken-html.php
- passwordResteToken-text.php
In web.php I have
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => 'app\mail\layouts',
...
The advanced template uses
'viewPath' => '#common/mail',
But as i'm using basic template, its not in the common/mail folder.
In sendMail function in PasswordResetRequestForm.php i have
return \Yii::$app->mailer->compose(['html' => 'passwordResetToken-html', 'text' => 'passwordResetToken-text'], ['user' => $user])
...
However getting error
The view file does not exist: app\mail\layouts\passwordResetToken-html.php
I know this is going to be something small but for the life of me i cannot see it
Removed the 'viewPath' of config, as the doc don't use it.
So it works.
Is there a way to configure Yii such that it will no longer load any Javascript out of the Assets folder?
Make your own AssetManager or extend current
protected/components/DummyAssetManager.php:
class DummyAssetManager extends CApplicationComponent {
public function publish(){}
}
add into components array in
protected/config/main.php:
'assetManager'=>array(
'class'=>'DummyAssetManager',
),
You should consult the manual for a detailed description of
the assetManager options
I think you can try following option in your config/main.php
'components' => array(
'assetManager' => array(
'linkAssets' => true,
),
),
This will make asset files symbolic links to your original js/css sources. See linkAssets for more details on it.
If your PHP<5.3, or the OS it's running on doesn't support symbolic links, you won't be able to use 'linkAssets' option, in this case you can try:
'components' => array(
'assetManager' => array(
'forceCopy' => true,
),
),
This should update asset folder on every request. These two options are usually used during development process (btw, you can't use both) and should be removed from production.
PS: if you're sure that you haven't explicitly enabled ckeditor somewhere in your code and you're confident about your assetmanager calls throughout the code, check your layout and page for widgets that require this CKeditor, as Yii can't preload 'stuff' just randomly, it can be triggered by some preloaded component/extension or yii widget.