laravel homestead 项目api后台搭建(oauth登录授权+登录错误的异常处理+跨域)

459 阅读4分钟

一,下载 laravel 到本地

可以通过 composer 命令

composer create-project --prefer-dist laravel/laravel blog

blog为新建的项目名称

二 ,通过 barryvdh/laravel-ide-helper 安装ide提示插件

①通过composer 下载插件 具体命令如下:

composer require barryvdh/laravel-ide-helper

②安装成功后,将服务提供者添加到providers数组中config/app.php

Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class

③生成Laravel门面对应的PHPDoc

在使用这个扩展包之前,或许不少人已经碰到了使用PHPStorm不能自动补全门面(Facade)的问题,现在Laravel IDE Helper Generator 为我们带来了福音。我们使用如下命令生成包含门面补全信息的文件

php artisan ide-helper:generate  

注意:在此之前需要清除bootstrap/compiled.php,所以生成之前需要先运行php artisan clear-compiled然后运行php artisan optimize(laravel5.6就不要输入了);

④重启IDE再打开环境基本就好了。。然后就可以尝试追踪代码了。

三,安装passport

1. 使用 Composer 安装 Passport :
composer require laravel/passport
2. 接下来,将 Passport 的服务提供者注册到配置文件 config/app.php 的 providers 数组中:
Laravel\Passport\PassportServiceProvider::class,
3. Passport 服务提供器使用框架注册自己的数据库迁移目录,因此在注册提供器后,就应该运行 Passport 的迁移命令来自动创建存储客户端和令牌的数据表:
php artisan migrate
4. 接下来,运行 passport:install 命令来创建生成安全访问令牌时所需的加密密钥,同时,这条命令也会创建用于生成访问令牌的「个人访问」客户端和「密码授权」客户端:
php artisan passport:install
5. 上面命令执行后,请将 Laravel\Passport\HasApiTokens Trait 添加到 App\User 模型中,这个 Trait 会给你的模型提供一些辅助函数,用于检查已认证用户的令牌和使用范围:
<?php

namespace App;

use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}
6. 接下来,在 AuthServiceProvider 的 boot 方法中调用 Passport::routes 函数。这个函数会注册发出访问令牌并撤销访问令牌、客户端和个人访问令牌所必需的路由:
<?php

namespace App\Providers;

use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * 应用程序的策略映射。
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();
    }
}
7. 将配置文件 config/auth.php 中授权看守器 guards 的 api 的 driver 选项改为 passport。此调整会让你的应用程序在在验证传入的 API 的请求时使用 Passport 的 TokenGuard 来处理:
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],

如果对于相应的验证数据表有修改(比如:默认是验证users数据表里面的账号和密码),现在要修改成 admins数据表里面的方法,只需在config文件夹下面的 auth.php 里面的providers 里面设置一下就行了:

    'providers' => [
        'admins' => [
            'driver' => 'eloquent',
            'model' => \App\Models\Admin::class,
        ],
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
    ],
8.创建登录的账号和密码

image
这里的密码通过 bcrypt 方法生成 具体如下:

$password = bcrypt('zhutong123');

四,创建Auth控制器和相关逻辑方法

  1. 首先在Controllers文件下面建立API文件夹,再在里面建立Auth文件夹,在Auth文件夹里面创建 AuthController(如下图)
    image
  1. 在routes文件夹里面新建api文件夹(用来放置所有的api接口),再在里面新建auth.php登录的路由文件(如下图)
    image

好了之后,在auth.php文件里面新建 登录的路由

Route::post('login', 'AuthController@login')->name('login');
  1. 下面来填写AuthController里面登录逻辑
class AuthController extends Controller
{
    /**
     * Token 协议
     * @var string
     */
    protected $grantType = "password";
    /**
     * 客户端 client
     * @var
     */
    protected $clientId;
    /**
     * 客户端 secret
     * @var
     */
    protected $clientSecret;

    public function __construct()
    {
        $this->clientId = config('app.api_client_id');
        $this->clientSecret = config('app.api_client_secret');
    }

    public function login(Request $request)
    {
        //  验证用户名和密码不能为空等
        $validator = \Validator::make($request->all(), [
            'name'    => 'required',
            'password' => 'required',
        ], [
            'name.required'    => '用户名不能为空!',
            'password.required' => '密码不能为空!',
        ]);
        foreach ($validator->errors()->messages() as $error) {
            echo $error[0];
            break;
        }
        // 验证用户名和密码
        $credentials = [
            'name' => $request->name,
            'password' => $request->password,
        ];
        if (!\Auth::attempt($credentials)) {
            return "用户名或者密码不正确!";
        }
        // 获取token
        $data = $this->creatToken($request);
        return $data;
    }

    public function creatToken(Request $request)
    {
        $http = new Client();
        $url = url('oauth/token');
        $response = $http->post($url, [
            'form_params' => [
                'grant_type' => $this->grantType,
                'client_id' => $this->clientId,
                'client_secret' => $this->clientSecret,
                'username' => $request->name,
                'password' => $request->password,
                'scope' => null,
            ],
        ]);
        return json_decode((string) $response->getBody(), true);
    }
}

==如果自己要定义新的字段为登录的验证字段设置如下:==

在User.php里面设置自定义的验证类型

/**
 * 更改passport登录用户字段
 * @param $mobile
 * @return mixed
 */
    public function findForPassport($name)
    {
        return $this->where('name', $name)->first();
    }

4.在Providers文件夹下面的RouteServiceProvider.php 设置相应的中间件

    protected function mapApiRoutes()
    {
        Route::group([
            'prefix'     => 'api',
            'namespace'  => $this->namespace . '\API',
            'middleware' => 'api',
        ], function () {
            $routePath = 'routes/api/';
            Route::prefix('api')
                ->middleware('api')
                ->namespace($this->namespace)
                ->group(base_path('routes/api.php'));
            // 认证模块
            Route::prefix('auth')
                ->namespace('Auth')
                ->group(base_path($routePath . 'auth.php'));
            // 活动模块
            Route::prefix('activity')
                ->namespace('Activity')
                ->middleware(['auth:api'])
                ->group(base_path($routePath . 'activity.php'));
        });
    }

5.在postman里面 尝试登录

image
上面的结果为登录成功的

6.如果出现登录不成功的情况 可以重新生成 client_id 和 API_CLIENT_SECRET

php artisan passport:client --password

7.如果出现env读取变量为空的情况

可以通过命令对配置文件缓存进行删除

php artisan cache:clear  
php artisan config:clear 

image
上面的结果为登录成功的

五,各类的异常处理

一个系统的搭建,我们往往要对齐做 各类信息的异常报错处理,下面我们来做一个

首先:新建一个Tools文件夹(主要放置一些工具类方法),在新建Services文件夹和Contracts文件夹

image

UtilService.php //这个文件主要是对返回消息的处理

<?php
/**
 * Created by PhpStorm.
 * User: zhuto
 * Date: 2018/2/27
 * Time: 15:53
 */

namespace App\Tools\Services;

use App\Tools\Contracts\Code;

class UtilService
{
    public static function response($message, $code = Code::R_OK, $data = [])
    {
        $out = [
            'msg'  => $message,
            'code' => $code,
        ];
        if ($data) {
            array_walk_recursive($data, function (&$item, $key) {
                if (is_null($item)) {
                    $item = '';
                } elseif (is_bool($item)) {
                    $item = (true === $item) ? 1 : 0;
                }
            });
            $out['data'] = $data;
        }
        return \Response::make($out);
    }
}

HandleService.php //这个是处理异常的句柄服务

<?php

namespace App\Tools\Services;

class HandleService
{
    public static function exception(\Exception $exception, $statusCode = 500)
    {
        switch ($statusCode) {
            case 404;
                $errorCode = 404;
                $message = "没有找到页面!";
                break;
            case 401;
                $errorCode = 401;
                $message = "没有授权";
                break;
            case 405;
                $errorCode = 405;
                $message = "不允许此方法";
                break;
            default:
                $errorCode = $exception->getCode();
                $message = $exception->getMessage();
        }
        return UtilService::response($message, $errorCode)->setStatusCode($statusCode);
    }
}

契约文件夹里面新建Code.php,所谓契约类似接口,很多地方都可以调用

<?php
/**
 * Created by PhpStorm.
 * User: zhuto
 * Date: 2018/2/27
 * Time: 15:58
 */

namespace App\Tools\Contracts;

interface Code
{
    const R_OK = 0;
}

在之后 在异常处理的文件夹(Exceptions),Handle.php 文件里面 render 重写 调用上面的新建的HandleService服务,代码如下:

public function render($request, Exception $exception)
    {
        if ($request->is('api/*')) {
            // 如果是api请求
            if ($exception instanceof ModelNotFoundException
                || $exception instanceof NotFoundHttpException) {
                // 如果请求的资源不存在(例如文章没或者没有这个页面)
                return HandleService::exception($exception, 404);
            } elseif ($exception instanceof AuthenticationException) {
                // 如果没有权限

                return HandleService::exception($exception, 401);
            } elseif ($exception instanceof MethodNotAllowedException) {
                // 如果路由没有找到
                return HandleService::exception($exception, 405);
            } else {
                // 其他抛出的错误
                return HandleService::exception($exception);
            }
        }

        return parent::render($request, $exception);
    }

我们来测试一下,异常处理是否成功!

image

六,新建zh-cn的中文语言包处理

1. 新建zh-cn文件和相应的errors.php 错误文件

image

2. 编写errors.php

<?php
/**
 * Created by PhpStorm.
 * User: zhuto
 * Date: 2018/2/27
 * Time: 19:09
 */

use App\Tools\Contracts\Code;

return [
    Code::R_OK => '请求成功',
    // 有别的所谓的错误 继续添加
];

七,通过composer 安装 barryvdh/laravel-cors 跨域插件

  1. 安装插件
$ composer require barryvdh/laravel-cors
  1. 在config 下的app.php 的providers 数组中注册
Barryvdh\Cors\ServiceProvider::class,
  1. kernel.php (核心文件中) 注册HandleCors
    image
  2. 复制vendor/barryvdh/laravel-cors/config/cors.php,到app/config目录下面,也可以通过artisan 命令来执行
$ php artisan vendor:publish --provider = "Barryvdh\Cors\ServiceProvider"