Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Изящная форма входа в админку на Laravel и Sentry

Anna | 31.05.2014 | нет комментариев

При создании сайтов доводится некоторое время уделить форме ввода логина и пароля для доступа к панели управления. Для убыстрения процесса разработки, хочу поделиться рецептом приготовления примитивный, комфортной и изящной формы входа в админку.

Статья содержит изложение некоторых базовых приемов применения Laravel при разработки сайтов и будет пригодна тем, кто начинает постигать данный фреймворк. Для примера использую Ubuntu 12.04, PostgreSQL 9.3, Nginx 1.1.19, PHP 5.5.7, Composer и свежий план, сделанный с применением Laravel 4.1. Под управление PostgreSQL вертится база данных examples, к которой имеет доступ пользователь examples c одноименным паролем. Nginx же настроен таким образом, что при обращении по адресу http://examples.loc в браузере открывается основная страницу-заглушка, которая идет с Laravel в комплекте, с надписью «You have arrived.»

Все пути к редактируемым файлам указаны касательно директории плана.

Окружение

Вначале настраиваю локальное окружение в Laravel. Для этого создаю директорию app/config/local и добавляю в нее файл database.php:

<?php
/**
 * app/config/local/database.php
 */
return array(
    'default' => 'pgsql',

    'connections' => array(
        'pgsql' => array(
			'driver'   => 'pgsql',
			'host'     => 'localhost',
			'database' => 'examples',
			'username' => 'examples',
			'password' => 'examples',
			'charset'  => 'utf8',
			'prefix'   => '',
			'schema'   => 'public',
		),
    ),
);

Умоляю Laravel применять окружение local по умолчанию. Для этого редактирую файл bootstrap/start.php и заменяю строку 'your-machine-name' на '*':

// Фрагмент из bootstrap/start.php
$env = $app->detectEnvironment(array(

	'local' => array('*'),

));

Подключение Sentry

Ссылку на инструкцию по подключению Sentry дозволено обнаружить в конце статьи. Коротко, делаю следующее.
Добавляю в composer.json строку "cartalyst/sentry": "2.0.*" в блок require.

// Фрагмент composer.json
{
	"name": "laravel/laravel",
	"description": "The Laravel Framework.",
	"keywords": ["framework", "laravel"],
	"license": "MIT",
	"require": {
		"laravel/framework": "4.1.*",
		"cartalyst/sentry": "2.0.*"
	},
...

Исполняю команду:
$ composer update

Символ $ набирать не нужно

Символ $ обозначает что, нужно набрать в командной строке composer update

Добавляю в список сервис-провайдеров в файле app/config/app.php:
'Cartalyst\Sentry\SentryServiceProvider',

Добавляю в список псевдонимов в файле app/config/app.php:
'Sentry' => 'Cartalyst\Sentry\Facades\Laravel\Sentry',

Исполняю миграции Sentry:
$ php artisan migrate --package=cartalyst/sentry

Публикую конфигурационный файл Sentry:
$ php artisan config:publish cartalyst/sentry

Открываю на редактирование app/config/packages/cartalyst/sentry/config.php. Нахожу в нем строку'login_attribute' => 'email' и заменяю на 'login_attribute' => 'username', для того Дабы Sentry исполнял аутентификацию пользователя по его логину, а не e-mail.

При выполнении миграций Sentry была сделана таблица users, в которой есть поле email, но нет username. Следственно, Дабы Sentry работал, нужно добавить недостающее поле. Для этого создаю миграцию:
$ php artisan migrate:make alter_users_add_username

В директории app/database/migration появится файл имя, которого будет состоять из нынешней даты и времени и заканчивается на alter_users_add_username.php. Редактирую его дальнейшим образом:

<?php
/**
 * app/database/migration/0000_00_00_000000_alter_users_add_username.php
 */
use Illuminate\Database\Migrations\Migration;

class AlterUsersAddUsername extends Migration {

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up()
	{
        Schema::table('users', function($table)
        {
            $table->string('username');
        });
	}

	/**
	 * Reverse the migrations.
	 *
	 * @return void
	 */
	public function down()
	{
        Schema::table('users', function($table)
        {
            $table->dropColumn('username');
        });
	}

}

Для проверки миграции исполняю:
$ php artisan migrate

Для проверки, что миграция удачно откатывается, исполняю:
$ php artisan migrate:rollback

Создаю еще одну миграцию, которая добавляет в таблицу users запись о суперпользователе:
$ php artisan migrate:make add_user_admin

Нахожу в директории app/database/migrate файл, тот, что заканчивается на add_user_admin.php и редактирую его:

<?php
/**
 * app/database/migration/0000_00_00_000001_add_user_admin.php
 */
use Illuminate\Database\Migrations\Migration;

class AddUserAdmin extends Migration {

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up()
	{
        $user = Sentry::createUser(array(
            'username' => 'admin',
            'email' => 'admin@examples.loc',
            'password' => 'password',
            'activated' => 1,
            'permissions' => array(
                'superuser' => 1,
            ),
        ));
	}

	/**
	 * Reverse the migrations.
	 *
	 * @return void
	 */
	public function down()
	{
        User::where('username', '=', 'admin')->firstOrFail()->delete();
	}

}

Проверяю, как миграции накатываются и откатываются. И перехожу к созданию контроллера, тот, что будет отвечать за аутентификацию пользователей.

Форма входа

В директории app/controllers создаю файл AuthController.php:

<?php
/**
 * app/controllers/AuthController.php
 */
class AuthController extends BaseController {

     /**
     * Отображает страницу входа
     *
     * @return Illuminate\View\View
     */
    public function getLogin()
    {
        $title = 'Вход';
        return View::make('auth.login', compact('title'));
    }
}

Способ getLogin() передает заголовок страницы через переменную $title в представление auth.login, которое служит для отображения страницы входа в админку.

Создаю представление auth.login. Для этого в директорию app/views добавляю директорию auth и создаю в ней файл login.blade.php:

/**
 * app/views/auth/login.blade.php
 */
@extends('layout')

@section('main')
<div>
{{ Form::open(array('class' => 'form-signin')) }}

    @if (!$errors->isEmpty())
    <div>
        @foreach ($errors->all() as $error)
        <p>{{ $error }}</p>
        @endforeach
    </div>
    @endif

    <h2>{{ $title }}</h2>

    {{ Form::text('username', null, array('class' => 'form-control', 'placeholder' => 'Логин')) }}
    {{ Form::password('password', array('class' => 'form-control', 'placeholde' => 'Пароль')) }}

    <label>
        {{ Form::checkbox('remember-me', 1) }} Запомни меня
    </label>

    {{ Form::submit('Войти', array('class' => 'btn btn-lg btn-primary btn-block')) }}

{{ Form::close() }}
</div>
@stop

Образец login.blade.php расширяет образец layout.blade.php. Следственно создаю его в директорииapp/views:

/**
 * app/views/layout.blade.php
 */
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>{{ $title }}</title>

        @section('styles')
        {{ HTML::style('//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css') }}
        {{ HTML::style(URL::asset('styles/base.css')) }}
        @show
    </head>
    <body>
        @yield('main')

        @section('scripts')
        {{ HTML::script('//netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js') }}
        @show
    <body>
</html>

Позже того, как есть способ контроллера и возвращаемое им представление, нужно настроить роутинг, Дабы GET запросы, отправляемые по адресу http://examples.loc/login, обрабатывались способом getLogin(). Для этого добавляю в файл app/routes.php дальнейший код:

// Фрагмент app/routes.php
...
Route::group(array('before' => 'guest'), function () 
{
    Route::get('login', array(
        'as' => 'auth.login', 
        'uses' => 'AuthController@getLogin'
    ));
});

С поддержкой Route::get() определяю роут с именем auth.login, тот, что направляет GET запросы по адресу /login способу getLogin() контроллера AuthController.
Также разместил роут auth.login в группы роутов. Перед любым роутом, входящим в данную группу будет выполнятся фильтр guest. Данный фильтр обозначает, что обработка GET запросов по адресу /login будет протекать только в том случает, если пользователя является гостем, т.е. не авторизован.

Перепишу фильтр guest так, Дабы он применял Sentry. Для этого в файле app/filters.php изменю код фильтра guest:

// Фрагмент app/filters.php
...
Route::filter('guest', function()
{
	if (Sentry::check()) return Redirect::to('/');
});
...

Сейчас дозволено посмотреть, как выглядит форма входа в браузере. Для этого перехожу по адресуhttp://examples.loc/login и…

Вижу сообщение об ошибке Call to undefined method Illuminate\Cookie\CookieJar::get().

Легким движением Google выясняю, что Sentry 2.0 совместим с Laravel 4.0, но не совместим 4.1. Отлично, что теснее зарелизился Sentry 2.1. Дабы избавиться от ошибки, изменяю версию Sentry в composer.json на 2.1:

// Фрагмент composer.json
{
	"name": "laravel/laravel",
	"description": "The Laravel Framework.",
	"keywords": ["framework", "laravel"],
	"license": "MIT",
	"require": {
		"laravel/framework": "4.1.*",
		"cartalyst/sentry": "2.1.*"
	},
...

Исполняю команду:
$ composer update

Еще раз пытаюсь открыть http://examples.loc/login и вижу форму ввода логина и пароля. Для того Дабы форма выглядела изящно, нужно добавить немножко CSS. Для этого в директории public создаю директориюstyles и добавляю туда файл base.css:

/**
 * public/style/base.css 
 */
body {
    padding-top: 40px;
    padding-bottom: 40px;
    background-color: #eee;
}

.form-signin {
    max-width: 330px;
    padding: 15px;
    margin: 0 auto;
}

.form-signin .form-signin-heading,
.form-signin .checkbox {
    margin-bottom: 10px;
}

.form-signin .form-signin-heading {
    text-align: center;
}

.form-signin .checkbox {
    font-weight: normal;
}

.form-signin .form-control {
    position: relative;
    font-size: 16px;
    height: auto;
    padding: 10px;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

.form-signin .form-control:focus {
    z-index: 2;
}

.form-signin input[type="text"] {
    margin-bottom: -1px;
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}

.form-signin input[type="password"] {
    margin-bottom: 10px;
    border-top-left-radius: 0;
    border-top-right-radius: 0;
}

Контролеры

Сейчас форма отображается прекрасно, но при нажатии на кнопку «Войти», возвращается оплошность 404. Значит нужно добавить в AuthController обработчик POST запросов, отправляемых на адрес /login.

<?php
/**
 * app/controllers/AuthController.php
 */
class AuthController extends BaseController {

    /**
     * Отображает страницу входа
     *
     * @return Illuminate\View\View
     */
    public function getLogin()
    {
        $title = 'Вход';
        return View::make('auth.login', compact('title'));
    }

    /**
     * Аутентифицирует и редиректит в админку
     *
     * @return Illuminate\Http\RedirectResponse
     */
    public function postLogin()
    {
        Input::flash();

        try {
            $credentials = array(
                'username' => Input::get('username'), 
                'password' => Input::get('password')
            );
            $user = Sentry::authenticate($credentials, Input::get('remember-me'));
        } catch (Exception $e) {
            return Redirect::to(route('auth.login'))
                ->withErrors(array($e->getMessage()));
        }

        return Redirect::intended(route('admin'));
    }

    /**
     * Обрабатывает выход
     *
     * @return Illuminate\Http\RedirectResponse
     */
    public function getLogout()
    {
        Sentry::logout();
        return Redirect::route('auth.login');
    }
}

В способе postLogin() данные, переданные через форму сохраняются в сессии с поддержкойInput::flash(). В блоке try Sentry пытается аутентифицировать пользователя. Если в форме ввода логина и пароля пользователь установит галочку «Запомни меня», то вторым параметром в Sentry::authenticate()будет передано значение true и Sentry запомнит пользователя в случае удачной аутентификации. Если аутентификация по какой-либо причине не прошла удачно, то в блоке catch способ Redirect::to() отправит нас на страницу ввода логина и пароля в месте с сообщением об ошибке. В случае удачной аутентификации способ Redirect::intended() отправит пользователя на ту страницу, на которую он намеревался зайти, когда был перенаправлен на форму ввода логина и пароля. Если такая страница не задана, то откроется страница по адресу /admin, с которой связан роут с именем admin.

Способ getLogin() самая примитивна реализация как дозволено разлогинить пользователя. Позже выхода пользователь будет перенаправление на страницу ввода логина и пароля.

Раньше чем переходить к настройке роутинга, нужно добавить способ, тот, что будет обрабатывать запросы, отправляемые по адресу /admin. Для этого отредактирую файл app/controllers/HomeController.phpдальнейшим образом:

<?php
/**
 *  app/controllers/HomeController.php
 */
class HomeController extends BaseController {

	public function showWelcome()
	{
		return View::make('hello');
	}

	public function getAdmin()
	{
		return link_to(route('auth.logout'), 'Выход');
	}

}

Способ getAdmin() легко отображает на страницу ссылку «Выход», при нажатии на которою пользователь будет разлогиниваться.

Роутинг

Сейчас, Дабы новые способы могли обрабатывать запрос, отредактирую в файл app/routes.php:

/**
 * app/routes.php
 */
Route::get('/', function()
{
	return View::make('hello');
});

Route::group(array('before' => 'guest'), function () 
{
    Route::get('login', array(
        'as' => 'auth.login', 
        'uses' => 'AuthController@getLogin'
    ));

    Route::post('login', array(
        'before' => 'csrf',
        'uses' => 'AuthController@postLogin'
    ));
});

Route::group(array('before' => 'auth'), function ()
{
    Route::get('admin', array(
        'as' => 'admin',
        'uses' => 'HomeController@getAdmin',
    ));

    Route::get('logout', array(
        'as' => 'auth.logout',
        'uses' => 'AuthController@getLogout'
    ));
}); 

Первая группа роутов, перед которой выполняется фильтр guest, содержи роутинг для адреса /login для GET и POST запросов. Фильтр guest обозначает, что по адресу /login будут обрабатываться запросы только от гостей, т.е. неавторизованных пользователей.

Вторая группа роутов, перед которой выполняется фильтр auth, содержит роутинг для адресов /admin и/logout. Фильтр auth обозначает, что по данным адресам будут обрабатываться запросы только от авторизованных пользователей.

Также нужно отредактировать фильтр auth, так Дабы он применял Sentry. Для этого открываю файлapp/filters.php изменяю фильтр auth дальнейшим образом:

// Фрагмент app/filters.php
...
Route::filter('auth', function()
{
	if (!Sentry::check()) return Redirect::guest(route('auth.login'));
});
...

Сейчас дозволено пробовать логиниться в админку использую логин admin и пароль password. Неавторизованному пользователю не удастся зайти на страницу /admin, она будет доступна, только позже удачной аутентификации. Также позже аутентификации будет немыслимо зайти на страницу /login, так как будет протекать редирект на основную страницу.

Верю данный пример поможет начинающим разработчикам отменнее осознать некоторые элементы Laravel.

Ссылки по теме

getcomposer.org/doc/00-intro.md#installation-nix
laravel.com/docs/installation#install-laravel
cartalyst.com/manual/sentry/installation/laravel-4

Источник: programmingmaster.ru
Оставить комментарий
БАЗА ЗНАНИЙ
СЛУЧАЙНАЯ СТАТЬЯ
СЛУЧАЙНЫЙ БЛОГ
СЛУЧАЙНЫЙ МОД
СЛУЧАЙНЫЙ СКИН
НОВЫЕ МОДЫ
НОВЫЕ СКИНЫ
НАКОПЛЕННЫЙ ОПЫТ
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB