Project
composer create-project laravel/laravel laravel-system-admin && cd laravel-system-admin
vim .env
APP_SALT="salt"
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=db
DB_USERNAME=root
DB_PASSWORD="password"
IDE
composer require --dev barryvdh/laravel-ide-helper
vim app/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
}
public function register()
{
if ($this->app->environment() !== 'production') {
$this->app->register(\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class);
}
}
}
php artisan ide-helper:generate
Hasher
mkdir -p app/Services/Auth
vim app/Services/Auth/PasswordHasher.php
<?php
namespace App\Services\Auth;
use Illuminate\Hashing\BcryptHasher;
class PasswordHasher extends BcryptHasher
{
protected $salt;
public function __construct()
{
parent::__construct();
$this->salt = env('APP_SALT');
}
public function make($value, array $options = [])
{
return parent::make(hash('sha256', $value . $this->salt));
}
public function check($value, $hashedValue, array $options = [])
{
return parent::check(hash('sha256', $value . $this->salt), $hashedValue);
}
}
Provider
vim app/Providers/AuthServiceProvider.php
<?php
namespace App\Providers;
use App\Services\Auth\PasswordHasher;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
public function boot()
{
$this->registerPolicies();
Auth::guard('admin')->getProvider()->setHasher($this->app['passwordHasher']);
}
public function register()
{
$this->app->singleton('passwordHasher', function () {
return new PasswordHasher();
});
}
}
Config
vim config/auth.php
<?php
return [
'guards' => [
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
'providers' => [
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
],
];
Model
php artisan make:model Models/Admin
vim app/Models/Admin.php
<?php
namespace App\Models;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
use Notifiable;
protected $table = 'admin';
protected $fillable = [
'nick_name', 'unique_name', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
}
Route
vim routes/web.php
<?php
Route::get('/', function () {
return view('welcome');
});
Route::post('/login', function () {
$credential = [
'unique_name' => '18020125636',
'password' => '18020125636'
];
if(! Auth::guard('admin')->attempt($credential)) {
return [ 'code' => -1 ];
}
return [ 'code' => 0 ];
});
CSRF
vim app/Http/Middleware/VerifyCsrfToken.php
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
protected $except = [
'login'
];
}
php artisan serve
curl -X POST http://127.0.0.1:8000/login | json
{
"code": 0
}
Redis
docker run --name laravel-system-admin -p 6379:6379 -d redis
composer require predis/predis
vim .env
SESSION_DRIVER=redis
Route
vim routes/web.php
<?php
Route::post('/login', function () {
$credential = [
'unique_name' => '18020125636',
'password' => '18020125636'
];
if(! Auth::guard('admin')->attempt($credential)) {
return [ 'code' => -1 ];
}
$user = Auth::guard('admin')->user();
return [
'code' => 0,
'data' => $user,
];
});
Route::group(['middleware' => 'auth:admin'], function () {
Route::get('/user', function () {
return 'user';
});
});
php artisan serve
curl localhost:8000 # Page not found
curl localhost:8000/user # AuthenticationException
Exception
vim app/Exceptions/Handler.php
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class Handler extends ExceptionHandler
{
protected $dontReport = [
];
protected $dontFlash = [
'password',
'password_confirmation',
];
public function report(Exception $exception)
{
parent::report($exception);
}
public function render($request, Exception $exception)
{
if ($exception instanceof NotFoundHttpException) {
return response()->json(['message' => $exception->getMessage()], 404);
} else if ($exception instanceof AuthenticationException) {
return response()->json(['message' => $exception->getMessage()], 401);
}
return parent::render($request, $exception);
}
}
php artisan serve
curl localhost:8000 | json
{
"message": ""
}
curl -c cookies -X POST localhost:8000/login | json
{
"code": 0,
"data": {
"id": 6,
"created_at": "2018-01-15 09:34:16",
"updated_at": "2018-07-23 17:55:27",
"nick_name": "王世新",
"unique_name": "18020125636",
"is_active": 1
}
}
curl -b cookies localhost:8000/user # user
Controller
php artisan make:controller AuthorizationsController
vim app/Http/Controllers/AuthorizationsController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
class AuthorizationsController extends Controller
{
public function store() {
$credential = [
'unique_name' => '18020125636',
'password' => '18020125636'
];
if(! Auth::guard('admin')->attempt($credential)) {
return [ 'code' => -1 ];
}
$user = Auth::guard('admin')->user();
return [
'code' => 0,
'data' => $user,
];
}
}
vim routes/web.php
<?php
Route::post('/login', 'AuthorizationsController@store')->name('auth.login');;
Route::group(['middleware' => 'auth:admin'], function () {
Route::get('/user', function () {
return 'user';
});
});
Request
php artisan make:request AuthorizationRequest
vim app/Http/Requests/AuthorizationRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class AuthorizationRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'unique_name' => 'required|string',
'password' => 'required|string|min:6',
];
}
}
vim app/Http/Controllers/AuthorizationsController.php
<?php
namespace App\Http\Controllers;
use App\Http\Requests\AuthorizationRequest;
use Illuminate\Support\Facades\Auth;
class AuthorizationsController extends Controller
{
public function store(AuthorizationRequest $request) {
$credentials['unique_name'] = $request->unique_name;
$credentials['password'] = $request->password;
if(! Auth::guard('admin')->attempt($credentials)) {
return [ 'code' => -1 ];
}
$user = Auth::guard('admin')->user();
return [
'code' => 0,
'data' => $user,
];
}
}
vim app/Exceptions/Handler.php
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class Handler extends ExceptionHandler
{
protected $dontReport = [
];
protected $dontFlash = [
'password',
'password_confirmation',
];
public function report(Exception $exception)
{
parent::report($exception);
}
public function render($request, Exception $exception)
{
if ($exception instanceof NotFoundHttpException) {
return response()->json(['message' => $exception->getMessage()], 404);
} else if ($exception instanceof AuthenticationException) {
return response()->json(['message' => $exception->getMessage()], 401);
} else if ($exception instanceof ValidationException) {
return response()->json([
'status_code' => 400,
'message' => $exception->getMessage(),
], 200);
}
return parent::render($request, $exception);
}
}
Resource
php artisan make:resource JsonModel
vim app/Http/Resources/JsonModel.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class JsonModel extends JsonResource
{
protected $result;
const KEY_CACHE_HEADER = 'XETag';
const KEY_CODE = 'XCmdrCode';
const KEY_MESSAGE = 'XCmdrMessage';
const KEY_RESULT = 'XCmdrResult';
public function __construct($variables, $code = JsonCode::SUCCESS, $message = null)
{
$data = [self::KEY_CACHE_HEADER => ''];
$data [self::KEY_CODE] = $code;
$data [self::KEY_MESSAGE] = $message ?? JsonCode::getCodeMessage($code);
$data [self::KEY_RESULT] = $variables;
parent::__construct($data);
$this->result = $data;
}
public function toArray($request)
{
return $this->result;
}
}
vim app/Http/Resources/JsonCode.php
<?php
namespace App\Http\Resources;
class JsonCode
{
const SUCCESS = 0;
// HTTP 请求方法不正确
const HTTP_METHOD_INVALID = 100;
// HTTP请求必须为GET
const HTTP_METHOD_MUST_BE_GET = 110;
// HTTP请求必须为POST
const HTTP_METHOD_MUST_BE_POST = 120;
// HTTP请求必须为DELETE
const HTTP_METHOD_MUST_BE_DELETE = 130;
// 没有权限
const PERMISSION_INVALID = 200;
// 没有指挥官权限
const TENANT_PERMISSION_INVALID = 201;
// 未登录
const LOGIN_REQUIRED = 210;
// 数据不正确
const DATA_INVALID = 300;
// 不被识别的数据类型
const DATA_UNRECOGNIZED = 310;
// 数据格式不正确
const DATA_FORMAT_INVALID = 311;
// 表单数据不正确
const DATA_FORM_INVALID = 320;
// 数据已存在
/** @deprecated use RESOURCE_NOT_EXIST instead */
const DATA_EXIST = 330;
// 电话号码已存在
const DATA_PHONE_EXIST = 331;
// 数据不存在
const DATA_NOT_EXIST = 340;
// 电话号码不存在
const DATA_PHONE_NOT_EXIST = 341;
// 参数错误
const DATA_FIELD_INVALID = 350;
// 验证码不正确
const DATA_VERIFY_CODE_INVALID = 351;
// 验证码失效
const DATA_VERIFY_CODE_FAILED = 352;
// 验证码发送失败
const DATA_VERIFY_CODE_SEND_FAILED = 353;
// 获取用户信息失败
const AUTH_FAILED = 400;
// 用户身份异常
const AUTH_IDENTITY_ABNORMAL = 410;
// 用户未激活
const AUTH_IDENTITY_NOT_ACTIVE = 411;
// 登录失败
const LOGIN_FAILED = 420;
// 微信用户不存在
const WEUSER_NOT_EXIST = 421;
// 平台账号不存在
const PASSPORT_NOT_EXIST = 422;
// 没有可用的帐户
const USERS_NOT_EXIST = 423;
// 租户正在审核中
const TENANT_CHECKING = 424;
// 客户端类型错误
const CLIENT_INVALID = 500;
// 操作失败
const OPERATE_FAILED = 600;
// 操作次数已达上限
const REACH_THE_MAX = 610;
// 资源无效
const RESOURCE_INVALID = 700;
// 资源不存在
const RESOURCE_NOT_EXIST = 710;
// 租户不存在
const TENANT_NOT_EXIST = 711;
// 资源已存在
const RESOURCE_EXIST = 720;
// 资源未改变
const RESOURCE_NOT_MODIFIED = 730;
// 资源已改变
const RESOURCE_MODIFIED = 740;
// API无效
const API_INVALID = 800;
private static $json_code_messages = [
self::SUCCESS => '成功',
self::HTTP_METHOD_INVALID => '错误的请求',
self::HTTP_METHOD_MUST_BE_GET => '必须为GET请求',
self::HTTP_METHOD_MUST_BE_POST => '必须为POST请求',
self::HTTP_METHOD_MUST_BE_DELETE => '必须为DELETE请求',
self::PERMISSION_INVALID=> '没有权限',
self::TENANT_PERMISSION_INVALID => '没有指挥官权限',
self::LOGIN_REQUIRED => '未登录',
self::DATA_INVALID => '数据不正确',
self::DATA_UNRECOGNIZED => '不被识别的数据类型',
self::DATA_FORMAT_INVALID => '数据格式不正确',
self::DATA_FORM_INVALID => '表单数据不正确',
self::DATA_EXIST => '数据已存在',
self::DATA_PHONE_EXIST => '电话号码已存在',
self::DATA_NOT_EXIST => '数据不存在',
self::DATA_PHONE_NOT_EXIST => '电话号码不存在',
self::DATA_FIELD_INVALID => '参数错误',
self::DATA_VERIFY_CODE_INVALID => '验证码不正确',
self::DATA_VERIFY_CODE_FAILED => '验证码失效',
self::AUTH_FAILED => '获取用户信息失败',
self::AUTH_IDENTITY_ABNORMAL => '用户身份异常',
self::AUTH_IDENTITY_NOT_ACTIVE => '用户未激活',
self::LOGIN_FAILED => '登录失败',
self::WEUSER_NOT_EXIST => '微信用户不存在',
self::PASSPORT_NOT_EXIST => '平台账号不存在',
self::USERS_NOT_EXIST => '没有可用的帐户',
self::TENANT_CHECKING => '租户正在审核中',
self::CLIENT_INVALID => '客户端类型错误',
self::OPERATE_FAILED => '操作失败',
self::REACH_THE_MAX => '操作次数已达上限',
self::RESOURCE_INVALID => '资源无效',
self::RESOURCE_NOT_EXIST => '资源不存在',
self::TENANT_NOT_EXIST => '租户不存在',
self::RESOURCE_EXIST => '资源已存在',
self::RESOURCE_NOT_MODIFIED => '资源未改变',
self::RESOURCE_MODIFIED => '资源已改变',
self::API_INVALID => 'API无效',
self::DATA_VERIFY_CODE_SEND_FAILED => '验证码发送失败'
];
public static function getCodeMessage($code)
{
return isset($code, self::$json_code_messages) ? self::$json_code_messages [$code] : '';
}
}
vim app/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Http\Resources\Json\Resource;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Resource::withoutWrapping();
}
public function register()
{
if ($this->app->environment() !== 'production') {
$this->app->register(\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class);
}
}
}
vim app/Http/Controllers/AuthorizationsController.php
<?php
namespace App\Http\Controllers;
use App\Http\Requests\AuthorizationRequest;
use App\Http\Resources\JsonModel;
use Illuminate\Support\Facades\Auth;
class AuthorizationsController extends Controller
{
public function store(AuthorizationRequest $request) {
$credentials['unique_name'] = $request->unique_name;
$credentials['password'] = $request->password;
if(! Auth::guard('admin')->attempt($credentials)) {
return [ 'code' => -1 ];
}
$user = Auth::guard('admin')->user();
return new JsonModel($user);
}
}
php artisan serve
curl -X POST \
http://127.0.0.1:8000/login \
-H 'content-type: application/json' \
-d '{
"unique_name": "18020125636",
"password": "18020125636"
}' | json
{
"XETag": "",
"XCmdrCode": 0,
"XCmdrMessage": "成功",
"XCmdrResult": {
"id": 6,
"created_at": "2018-01-15 09:34:16",
"updated_at": "2018-07-23 17:55:27",
"nick_name": "王世新",
"unique_name": "18020125636",
"is_active": 1
}
}
Controller
php artisan make:controller MachinesController
vim app/Http/Controllers/MachinesController.php
<?php
namespace App\Http\Controllers;
use App\Http\Resources\JsonModel;
class MachinesController extends Controller
{
public function index() {
return new JsonModel([]);
}
}
Route
vim routes/web.php
<?php
Route::post('/login', 'AuthorizationsController@store')->name('auth.login');
Route::group(['middleware' => 'auth:admin'], function () {
Route::get('/user', function () {
return 'user';
});
});
Route::get('/machines', 'MachinesController@index')->name('machines.index');
Query
vim app/Http/Controllers/MachinesController.php
<?php
namespace App\Http\Controllers;
use App\Http\Resources\JsonModel;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
class MachinesController extends Controller
{
public function index(Request $request) {
$online = $request->query('online');
$count_per_page = $request->query('count_per_page', 10);
$qb = DB::table('machine AS m')
->leftJoin('machine_online_state AS s', 's.machine_id', '=', 'm.id');
if ($online) {
$qb->where('s.state', 'online');
}
$machines = $qb->where('m.deleted', 0)->paginate($count_per_page);
return new JsonModel([ 'data_list' => $machines ]);
}
}
Model
php artisan make:model Models/Category
vim app/Models/Category.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
protected $table = 'category';
}
php artisan make:model Models/Machine
vim app/Models/Machine.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Machine extends Model
{
protected $table = 'machine';
public function category()
{
return $this->hasOne('App\Models\Category', 'id', 'category_id');
}
}
vim app/Http/Controllers/MachinesController.php
<?php
namespace App\Http\Controllers;
use App\Http\Resources\JsonModel;
use App\Models\Machine;
use Illuminate\Http\Request;
class MachinesController extends Controller
{
public function index(Request $request) {
$online = $request->query('online');
$count_per_page = $request->query('count_per_page', 10);
$qb = Machine::leftJoin('machine_online_state AS s', 's.machine_id', '=', 'machine.id');
if ($online) {
$qb->where('s.state', 'online');
}
$qb = $qb->where('machine.deleted', 0);
$paginator = $qb->simplePaginate($count_per_page);
return new JsonModel([ 'data_list' => $paginator ]);
}
}
Paginator
vim app/Http/Resources/PaginatorJsonModel.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Pagination\LengthAwarePaginator;
class PaginatorJsonModel extends JsonModel
{
const KEY_DATA_LIST = 'data_list';
const KEY_TOTAL_ITEM_COUNT = 'total_item_count';
const KEY_TOTAL_PAGE_COUNT = 'total_page_count';
public function __construct(ResourceCollection $variables)
{
$resource = $variables->resource;
if (! $resource instanceof LengthAwarePaginator) {
throw new \InvalidArgumentException("class_name must be instance of ".LengthAwarePaginator::class."!");
}
$data = [
self::KEY_DATA_LIST => $variables,
self::KEY_TOTAL_ITEM_COUNT => $resource->count(),
self::KEY_TOTAL_PAGE_COUNT => $resource->lastPage(),
];
parent::__construct($data);
}
}
php artisan make:resource MachinesResource
vim app/Http/Resources/MachinesResource.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class MachinesResource extends JsonResource
{
public function toArray($request)
{
$machine = $this;
$category = $machine->category;
return [
'id' => $machine->id,
'machine_name' => $machine->machine_name,
'category' => [
'id' => $category->id,
'category_name' => $category->category_name,
],
];
}
}
vim app/Http/Controllers/MachinesController.php
<?php
namespace App\Http\Controllers;
use App\Http\Resources\MachinesResource;
use App\Http\Resources\PaginatorJsonModel;
use App\Models\Machine;
use Illuminate\Http\Request;
class MachinesController extends Controller
{
public function index(Request $request) {
$online = $request->query('online');
$count_per_page = $request->query('count_per_page', 10);
$qb = Machine::leftJoin('machine_online_state AS s', 's.machine_id', '=', 'machine.id');
if ($online) {
$qb->where('s.state', 'online');
}
$qb = $qb->where('machine.deleted', 0);
$paginator = $qb->paginate($count_per_page);
return new PaginatorJsonModel(MachinesResource::collection($paginator));
}
}