finish basic

This commit is contained in:
guaosi 2019-03-01 14:08:34 +08:00
commit 31c665249f
130 changed files with 11683 additions and 0 deletions

15
.editorconfig Normal file
View File

@ -0,0 +1,15 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.yml]
indent_size = 2

41
.env.example Normal file
View File

@ -0,0 +1,41 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=redis
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
HORIZON_IP=127.0.0.1

5
.gitattributes vendored Normal file
View File

@ -0,0 +1,5 @@
* text=auto
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
CHANGELOG.md export-ignore

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
/node_modules
/public/hot
/public/storage
/storage/*.key
/vendor
.env
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log

View File

@ -0,0 +1,5 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" />
</settings>
</component>

6
.idea/misc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/test.iml" filepath="$PROJECT_DIR$/.idea/test.iml" />
</modules>
</component>
</project>

8
.idea/test.iml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

10
.idea/workspace.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NodePackageJsonFileManager">
<packageJsonPaths />
</component>
<component name="PropertiesComponent">
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
</component>
</project>

View File

@ -0,0 +1,133 @@
<?php
namespace App\Api\Helpers;
use Symfony\Component\HttpFoundation\Response as FoundationResponse;
use Response;
trait ApiResponse
{
/**
* @var int
*/
protected $statusCode = FoundationResponse::HTTP_OK;
/**
* @return mixed
*/
public function getStatusCode()
{
return $this->statusCode;
}
/**
* @param $statusCode
* @return $this
*/
public function setStatusCode($statusCode,$httpCode=null)
{
$httpCode = $httpCode ?? $statusCode;
$this->statusCode = $statusCode;
return $this;
}
/**
* @param $data
* @param array $header
* @return mixed
*/
public function respond($data, $header = [])
{
return Response::json($data,$this->getStatusCode(),$header);
}
/**
* @param $status
* @param array $data
* @param null $code
* @return mixed
*/
public function status($status, array $data, $code = null){
if ($code){
$this->setStatusCode($code);
}
$status = [
'status' => $status,
'code' => $this->statusCode
];
$data = array_merge($status,$data);
return $this->respond($data);
}
/**
* @param $message
* @param int $code
* @param string $status
* @return mixed
*/
/*
* 格式
* data:
* code:422
* message:xxx
* status:'error'
*/
public function failed($message, $code = FoundationResponse::HTTP_BAD_REQUEST,$status = 'error'){
return $this->setStatusCode($code)->message($message,$status);
}
/**
* @param $message
* @param string $status
* @return mixed
*/
public function message($message, $status = "success"){
return $this->status($status,[
'message' => $message
]);
}
/**
* @param string $message
* @return mixed
*/
public function internalError($message = "Internal Error!"){
return $this->failed($message,FoundationResponse::HTTP_INTERNAL_SERVER_ERROR);
}
/**
* @param string $message
* @return mixed
*/
public function created($message = "created")
{
return $this->setStatusCode(FoundationResponse::HTTP_CREATED)
->message($message);
}
/**
* @param $data
* @param string $status
* @return mixed
*/
public function success($data, $status = "success"){
return $this->status($status,compact('data'));
}
/**
* @param string $message
* @return mixed
*/
public function notFond($message = 'Not Fond!')
{
return $this->failed($message,Foundationresponse::HTTP_NOT_FOUND);
}
}

View File

@ -0,0 +1,109 @@
<?php
namespace App\Api\Helpers;
use Exception;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
class ExceptionReport
{
use ApiResponse;
/**
* @var Exception
*/
public $exception;
/**
* @var Request
*/
public $request;
/**
* @var
*/
protected $report;
/**
* ExceptionReport constructor.
* @param Request $request
* @param Exception $exception
*/
function __construct(Request $request, Exception $exception)
{
$this->request = $request;
$this->exception = $exception;
}
/**
* @var array
*/
//当抛出这些异常时可以使用我们定义的错误信息与HTTP状态码
//可以把常见异常放在这里
public $doReport = [
AuthenticationException::class => ['未授权',401],
ModelNotFoundException::class => ['该模型未找到',404],
AuthorizationException::class => ['没有此权限',403],
ValidationException::class => [],
UnauthorizedHttpException::class=>['未登录或登录状态失效',422],
TokenInvalidException::class=>['token不正确',400],
NotFoundHttpException::class=>['没有找到该页面',404],
MethodNotAllowedHttpException::class=>['访问方式不正确',405],
];
public function register($className,callable $callback){
$this->doReport[$className] = $callback;
}
/**
* @return bool
*/
public function shouldReturn(){
//只有请求包含是json或者ajax请求时才有效
// if (! ($this->request->wantsJson() || $this->request->ajax())){
//
// return false;
// }
foreach (array_keys($this->doReport) as $report){
if ($this->exception instanceof $report){
$this->report = $report;
return true;
}
}
return false;
}
/**
* @param Exception $e
* @return static
*/
public static function make(Exception $e){
return new static(\request(),$e);
}
/**
* @return mixed
*/
public function report(){
if ($this->exception instanceof ValidationException){
$error = array_first($this->exception->errors());
return $this->failed(array_first($error),$this->exception->status);
}
$message = $this->doReport[$this->report];
return $this->failed($message[0],$message[1]);
}
public function prodReport(){
return $this->failed('服务器错误','500');
}
}

42
app/Console/Kernel.php Normal file
View File

@ -0,0 +1,42 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
//
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')
// ->hourly();
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace App\Exceptions;
use App\Api\Helpers\ExceptionReport;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array
*/
protected $dontFlash = [
'password',
'password_confirmation',
];
/**
* Report or log an exception.
*
* @param \Exception $exception
* @return void
*/
public function report(Exception $exception)
{
parent::report($exception);
}
public function render($request, Exception $exception)
{
//ajax请求我们才捕捉异常
if ($request->ajax()){
// 将方法拦截到自己的ExceptionReport
$reporter = ExceptionReport::make($exception);
if ($reporter->shouldReturn()){
return $reporter->report();
}
if(env('APP_DEBUG')){
//开发环境,则显示详细错误信息
return parent::render($request, $exception);
}else{
//线上环境,未知错误则显示500
return $reporter->prodReport();
}
}
return parent::render($request, $exception);
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Requests\Api\UserRequest;
use App\Http\Resources\Api\AdminResource;
use App\Jobs\Api\SaveLastTokenJob;
use App\Models\Admin;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
class AdminController extends Controller
{
//返回用户列表
public function index()
{
//3个用户为一页
$admins = Admin::paginate(3);
return AdminResource::collection($admins);
}
//返回单一用户信息
public function show(Admin $admin)
{
return $this->success(new AdminResource($admin));
}
//返回当前登录用户信息
public function info()
{
$admins = Auth::user();
return $this->success(new AdminResource($admins));
}
//用户注册
public function store(UserRequest $request)
{
$admin = Admin::create($request->all());
if ($admin) {
return $this->setStatusCode(201)->success('用户注册成功');
}
return $this->failed('用户注册失败');
}
//用户登录
public function login(Request $request)
{
//获取当前守护的名称
$present_guard = Auth::getDefaultDriver();
$token = Auth::claims(['guard'=>$present_guard])->attempt(['name' => $request->name, 'password' => $request->password]);
if ($token) {
//如果登陆先检查原先是否有存token有的话先失效然后再存入最新的token
$user = Auth::user();
if ($user->last_token) {
try{
Auth::setToken($user->last_token)->invalidate();
}catch (TokenExpiredException $e){
//因为让一个过期的token再失效会抛出异常所以我们捕捉异常不需要做任何处理
}
}
SaveLastTokenJob::dispatch($user,$token);
return $this->setStatusCode(201)->success(['token' => 'bearer ' . $token]);
}
return $this->failed('账号或密码错误', 400);
}
//用户退出
public function logout()
{
Auth::logout();
return $this->success('退出成功...');
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace App\Http\Controllers\Api;
use App\Api\Helpers\ApiResponse;
use App\Http\Controllers\Controller as BaseController;
class Controller extends BaseController
{
use ApiResponse;
// 其他通用的Api帮助函数
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Requests\Api\UserRequest;
use App\Http\Resources\Api\UserResource;
use App\Jobs\Api\SaveLastTokenJob;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
class UserController extends Controller
{
//返回用户列表
public function index(){
//3个用户为一页
$users = User::paginate(3);
return UserResource::collection($users);
}
//返回单一用户信息
public function show(User $user){
return $this->success(new UserResource($user));
}
//返回当前登录用户信息
public function info(){
$user = Auth::user();
return $this->success(new UserResource($user));
}
//用户注册
public function store(UserRequest $request){
$user = User::create($request->all());
if($user){
return $this->setStatusCode(201)->success('用户注册成功');
}
return $this->failed('用户注册失败');
}
//用户登录
public function login(Request $request){
$token=Auth::claims(['type'=>'api'])->attempt(['name'=>$request->name,'password'=>$request->password]);
if($token) {
//如果登陆先检查原先是否有存token有的话先失效然后再存入最新的token
$user = Auth::user();
if($user->last_token){
try{
Auth::setToken($user->last_token)->invalidate();
}catch (TokenExpiredException $e){
//因为让一个过期的token再失效会抛出异常所以我们捕捉异常不需要做任何处理
}
}
SaveLastTokenJob::dispatch($user,$token);
return $this->setStatusCode(201)->success(['token' => 'bearer ' . $token]);
}
return $this->failed('账号或密码错误',400);
}
//用户退出
public function logout(){
Auth::logout();
return $this->success('退出成功...');
}
public function test(Request $request){
$token = Auth::guard('api')->getToken();
$token = Auth::guard('admin')->setToken($token)->refresh();
dd(Auth::guard('admin')->setToken($token)->check());
return $token;
$token = Auth::guard('api')->getToken();
Auth::guard('api')->setToken($token)->invalidate();
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class ForgotPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset emails and
| includes a trait which assists in sending these notifications from
| your application to your users. Feel free to explore this trait.
|
*/
use SendsPasswordResetEmails;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| 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 = '/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function username()
{
return 'name';
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace App\Http\Controllers\Auth;
use FApp\Models\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:6', 'confirmed'],
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\Models\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Where to redirect users after resetting their password.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\VerifiesEmails;
class VerificationController extends Controller
{
/*
|--------------------------------------------------------------------------
| Email Verification Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling email verification for any
| user that recently registered with the application. Emails may also
| be re-sent if the user didn't receive the original email message.
|
*/
use VerifiesEmails;
/**
* Where to redirect users after verification.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

85
app/Http/Kernel.php Normal file
View File

@ -0,0 +1,85 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'cors'=> \Medz\Cors\Laravel\Middleware\ShouldGroup::class,
'api.refresh'=>\App\Http\Middleware\Api\RefreshTokenMiddleware::class,
'admin.refresh'=>\App\Http\Middleware\Api\RefreshAdminTokenMiddleware::class,
'admin.guard'=>\App\Http\Middleware\Api\AdminGuardMiddleware::class,
'api.guard'=>\App\Http\Middleware\Api\UserGuardMiddleware::class,
];
/**
* The priority-sorted list of middleware.
*
* This forces non-global middleware to always be in the given order.
*
* @var array
*/
protected $middlewarePriority = [
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\Authenticate::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
];
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Http\Middleware\Api;
use Closure;
class AdminGuardMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
*
* @return mixed
*/
public function handle($request, Closure $next)
{
config(['auth.defaults.guard'=>'admin']);
return $next($request);
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace App\Http\Middleware\Api;
use App\Jobs\Api\SaveLastTokenJob;
use Auth;
use Closure;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
// 注意,我们要继承的是 jwt 的 BaseMiddleware
class RefreshAdminTokenMiddleware extends BaseMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
*
* @return mixed
* @throws TokenInvalidException
*/
public function handle($request, Closure $next)
{
// 检查此次请求中是否带有 token如果没有则抛出异常。
$this->checkForToken($request);
//1. 格式通过验证是否是专属于这个的token
//获取当前守护的名称
$present_guard = Auth::getDefaultDriver();
//获取当前token
$token=Auth::getToken();
//即使过期了也能获取到token里的 载荷 信息。
$payload = Auth::manager()->getJWTProvider()->decode($token->get());
//如果不包含guard字段或者guard所对应的值与当前的guard守护值不相同
//证明是不属于当前guard守护的token
if(empty($payload['guard'])||$payload['guard']!=$present_guard){
throw new TokenInvalidException();
}
//使用 try 包裹,以捕捉 token 过期所抛出的 TokenExpiredException 异常
//2. 此时进入的都是属于当前guard守护的token
try {
// 检测用户的登录状态,如果正常则通过
if ($this->auth->parseToken()->authenticate()) {
return $next($request);
}
throw new UnauthorizedHttpException('jwt-auth', '未登录');
} catch (TokenExpiredException $exception) {
// 3. 此处捕获到了 token 过期所抛出的 TokenExpiredException 异常,我们在这里需要做的是刷新该用户的 token 并将它添加到响应头中
try {
// 刷新用户的 token
$token = $this->auth->refresh();
// 使用一次性登录以保证此次请求的成功
Auth::onceUsingId($this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']);
//刷新了token将token存入数据库
$user = Auth::user();
SaveLastTokenJob::dispatch($user,$token);
} catch (JWTException $exception) {
// 如果捕获到此异常,即代表 refresh 也过期了,用户无法刷新令牌,需要重新登录。
throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage());
}
}
// 在响应头中返回新的 token
return $this->setAuthenticationHeader($next($request), $token);
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace App\Http\Middleware\Api;
use App\Jobs\Api\SaveLastTokenJob;
use Auth;
use Closure;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Facades\JWTAuth;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
// 注意,我们要继承的是 jwt 的 BaseMiddleware
class RefreshTokenMiddleware extends BaseMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
*
* @return mixed
*/
public function handle($request, Closure $next)
{
// 检查此次请求中是否带有 token如果没有则抛出异常。
$this->checkForToken($request);
//1. 格式通过验证是否是专属于这个的token
//获取当前守护的名称
$present_guard = Auth::getDefaultDriver();
//获取当前token
$token=Auth::getToken();
//即使过期了也能获取到token里的 载荷 信息。
$payload = Auth::manager()->getJWTProvider()->decode($token->get());
//如果不包含guard字段或者guard所对应的值与当前的guard守护值不相同
//证明是不属于当前guard守护的token
if(empty($payload['guard'])||$payload['guard']!=$present_guard){
throw new TokenInvalidException();
}
//使用 try 包裹,以捕捉 token 过期所抛出的 TokenExpiredException 异常
//2. 此时进入的都是属于当前guard守护的token
try {
// 检测用户的登录状态,如果正常则通过
if ($this->auth->parseToken()->authenticate()) {
return $next($request);
}
throw new UnauthorizedHttpException('jwt-auth', '未登录');
} catch (TokenExpiredException $exception) {
// 此处捕获到了 token 过期所抛出的 TokenExpiredException 异常,我们在这里需要做的是刷新该用户的 token 并将它添加到响应头中
try {
// 刷新用户的 token
$token = $this->auth->refresh();
// 使用一次性登录以保证此次请求的成功
Auth::onceUsingId($this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']);
//刷新了token将token存入数据库
$user = Auth::user();
SaveLastTokenJob::dispatch($user,$token);
} catch (JWTException $exception) {
// 如果捕获到此异常,即代表 refresh 也过期了,用户无法刷新令牌,需要重新登录。
throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage());
}
}
// 在响应头中返回新的 token
return $this->setAuthenticationHeader($next($request), $token);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Http\Middleware\Api;
use Closure;
class UserGuardMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
*
* @return mixed
*/
public function handle($request, Closure $next)
{
config(['auth.defaults.guard'=>'api']);
return $next($request);
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
class CheckForMaintenanceMode extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.
*
* @var array
*/
protected $except = [
//
];
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
class EncryptCookies extends Middleware
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array
*/
protected $except = [
//
];
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/home');
}
return $next($request);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
class TrimStrings extends Middleware
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array
*/
protected $except = [
'password',
'password_confirmation',
];
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Fideloper\Proxy\TrustProxies as Middleware;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array
*/
protected $proxies;
/**
* The headers that should be used to detect proxies.
*
* @var int
*/
protected $headers = Request::HEADER_X_FORWARDED_ALL;
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
*
* @var bool
*/
protected $addHttpCookie = true;
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
//
];
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Http\Requests\Api;
class AdminRequest extends FormRequest
{
public function rules()
{
switch ($this->method()) {
case 'GET':
{
return [
'id' => ['required,exists:users,id']
];
}
case 'POST':
{
return [
'name' => ['required', 'max:12', 'unique:users,name'],
'password' => ['required', 'max:16', 'min:6']
];
}
case 'PUT':
case 'PATCH':
case 'DELETE':
default:
{
return [
];
}
}
}
public function messages()
{
return [
'id.required'=>'用户ID必须填写',
'id.exists'=>'用户不存在',
'name.unique' => '用户名已经存在',
'name.required' => '用户名不能为空',
'name.max' => '用户名最大长度为12个字符',
'password.required' => '密码不能为空',
'password.max' => '密码长度不能超过16个字符',
'password.min' => '密码长度不能小于6个字符'
];
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Http\Requests\Api;
use Illuminate\Foundation\Http\FormRequest as BaseFormRequest;
class FormRequest extends BaseFormRequest
{
public function authorize()
{
return true;
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Http\Requests\Api;
class UserRequest extends FormRequest
{
public function rules()
{
switch ($this->method()) {
case 'GET':
{
return [
'id' => ['required,exists:users,id']
];
}
case 'POST':
{
return [
'name' => ['required', 'max:12', 'unique:users,name'],
'password' => ['required', 'max:16', 'min:6']
];
}
case 'PUT':
case 'PATCH':
case 'DELETE':
default:
{
return [
];
}
}
}
public function messages()
{
return [
'id.required'=>'用户ID必须填写',
'id.exists'=>'用户不存在',
'name.unique' => '用户名已经存在',
'name.required' => '用户名不能为空',
'name.max' => '用户名最大长度为12个字符',
'password.required' => '密码不能为空',
'password.max' => '密码长度不能超过16个字符',
'password.min' => '密码长度不能小于6个字符'
];
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Http\Resources\Api;
use App\Models\Enum\AdminEnum;
use Illuminate\Http\Resources\Json\JsonResource;
class AdminResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id'=>$this->id,
'name' => $this->name,
'status' => AdminEnum::getStatusName($this->status),
'created_at'=>(string)$this->created_at,
'updated_at'=>(string)$this->updated_at
];
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Http\Resources\Api;
use App\Models\Enum\UserEnum;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
<