欢迎阅读该文章!
- 本教程使用laravel提供的auth组件来做的认证登录
- 本文教程只需要你安装了基本的laravel运行环境即可运行
一. 安装
安装tymon/jwt-auth
,代码如下:
composer require tymon/jwt-auth ^1.0 // 安装
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider" // 生成配置文件
php artisan jwt:secret // 初步密钥生成
二. 配置
认证配置修改
修改你的config/auth.php
文件,如下:
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
'hash' => false,
],
],
修改你的App/User.php
文件,如下:
<?php
namespace App;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
这里解析下:
laravel中的默认使用web
来进行认证的守卫,这里 jwt 主要是弄接口的嘛,所以自然而然的改成 api。守卫中的api
驱动也改成咱们下载下来即将要用到的jwt
。这样laravel的认证配置就大功告成了。
数据的初步生成
使用laravel的提供的auth,如下:
php artisan make:auth
- 好了,这是在
database/migrations
文件中生成了即将要迁移的用户数据表。 - 有了数据表还不够,咱们还需要往里面填充数据。执行
php artisan make:seeder UsersTableSeeder
命令在database/seeds
文件夹中会生成UsersTableSeeder.php
文件用来填充数据。该文件代码如下:use Illuminate\Database\Seeder; use App\User; use Illuminate\Contracts\Hashing\Hasher as HasherContract; class UsersTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run(HasherContract $hasher) { $arr = [ [ 'name' => 'jack', 'email' => '775893055@qq.com', 'password' => $hasher->make('123456'), ], [ 'name' => 'hurry', 'email' => '1041224389@qq.com', 'password' => $hasher->make('123456'), ], ]; User::insert($arr); } }
- 然后记得把
seeds\DatabaseSeeder.php
中的注释去掉<?php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { $this->call(UsersTableSeeder::class); } }
- 在
.env
文件中配置好你的数据库,执行:php artisan migrate --seed
- 路由配置,文件
routes\api.php
,如下:<?php use Illuminate\Http\Request; Route::middleware('auth:api')->get('/user', function (Request $request) { return $request->user(); }); Auth::routes();
三. 代码编写
Auth\LoginController.php
重写登录方法
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
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');
}
/**
* 重写登录方法(jwt)
*
* @param Request $request
* @return mixed
* @throws \Illuminate\Validation\ValidationException
*/
public function login(Request $request)
{
$this->validateLogin($request);
$credentials = $this->credentials($request);
if (!$token = auth()->attempt($credentials)) {
return $this->failed('登录失败,账号或者密码错误', '401');
}
return $this->success([
'access_token' => $token,
'token_type' => 'bearer',
'user' => auth()->user(),
'expires_in' => auth()->factory()->getTTL() * 60
]);
}
}
Exceptions\Handler.php
确保异常返回的是 json 格式
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use App\Http\Controllers\Controller;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* @var array
*/
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);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
if ($request->is("api/*")) {
if ($exception instanceof NotFoundHttpException) {
return (new Controller())->failed('路由没找到.');
}
if ($exception instanceof ValidationException) {
return (new Controller())->failed($exception->validator->errors()->first());
}
if ($exception->getPrevious() instanceof TokenExpiredException) {
return (new Controller())->failed('登录超时,请重新登录', 401);
}
return (new Controller())->failed($exception->getMessage());
}
return parent::render($request, $exception);
}
}
Controllers\Controllers.php
封装返回的统一消息
<?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;
use Response;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\Response as FoundationResponse;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
/**
* @var int
*/
protected $statusCode = FoundationResponse::HTTP_OK;
/**
* 获取响应http状态码
*
* @return mixed
*/
public function getStatusCode()
{
return $this->statusCode;
}
/**
* 设置响应http状态码
*
* @param $statusCode
* @return $this
*/
public function setStatusCode($statusCode)
{
$this->statusCode = $statusCode;
return $this;
}
/**
* 封装的底层http响应
*
* @param $data
* @param array $header
* @return mixed
*/
public function respond($data, $header = [])
{
return Response::json($data, $this->getStatusCode(), $header);
}
/**
* 封装status
*
* @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
];
if (config('app.debug')) {
$status['logs'] = DB::getQueryLog();
}
$data = array_merge($status, $data);
return $this->respond($data);
}
/**
* 消息响应
*
* @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 created($message = "created")
{
return $this->setStatusCode(FoundationResponse::HTTP_CREATED)
->message($message);
}
/**
* 通用返回
*
* @param $data
* @return mixed
*/
public function returnMsg($data)
{
if ($data['success'] == true) {
if ($data['data']) {
return $this->success($data['data']);
}
return $this->message($data['msg']);
} else {
return $this->failed($data['msg']);
}
}
/**
* 成功响应
*
* @param $data
* @param string $status
* @return mixed
*/
public function success($data, $status = "success")
{
if (isset($data['success']) && $data['success'] === false) {
return $this->returnMsg($data);
}
return $this->status($status, compact('data'));
}
/**
* 失败响应
*
* @param $message
* @param int $code
* @param string $status
* @return mixed
*/
public function failed($message = '操作失败', $code = FoundationResponse::HTTP_BAD_REQUEST, $status = 'error')
{
return $this->setStatusCode($code)->message($message, $status);
}
/**
* HTTP内部服务器错误
*
* @param string $message
* @return mixed
*/
public function internalError($message = "Internal Error!")
{
return $this->failed($message, FoundationResponse::HTTP_INTERNAL_SERVER_ERROR);
}
/**
* 不存在的api
*
* @param string $message
* @return mixed
*/
public function notFond($message = 'Not Fond!')
{
return $this->failed($message, FoundationResponse::HTTP_NOT_FOUND);
}
/**
* 接口未授权
*
* @param string $message
* @return mixed
*/
public function unAuthorized($message = "Unauthorized!")
{
return $this->failed($message, FoundationResponse::HTTP_UNAUTHORIZED);
}
/**
* 没有权限操作指定资源
*
* @param string $message
* @return mixed
*/
public function forbidden($message = "Forbidden!")
{
return $this->failed($message, FoundationResponse::HTTP_FORBIDDEN);
}
}
好了,完成上面代码的编写之后,咱们就可以登录了。访问接口/api/login
,进行登录:
emmmm,可以看到有返回到的token。接下来就把这个token带上头部就可以进行用户的认证了。
具体的方法是 Authorization: bearer +你的token,结合下面的中间键使用。基本满足用户认证,单点登录的需求了啦。
四. 中间键
Http\Kernel.php
文件中$routeMiddleware
数组:加上一行:
'jwt.auth' => \Tymon\JWTAuth\Http\Middleware\AuthenticateAndRenew::class,
这样,你就可以在需要认证的路由上面加上这个中间键就可以了。
五. 获取当前认证用户的方法
auth()->user() 或 $request->user()
好了。差不多就这样了。这里涵盖了laravel中api的基本搭建。
为了方便大家的理解:我弄了个小小的demo放上了github上面:
最后,如果发现有什么问题,错误的,私信我。尽快修正。
如果想搭建一个更具细节的Api开发环境,安利一篇博文:博客:手摸手教你让 Laravel 开发 API 更得心应手
努力,加油。
© 著作权归作者所有
发表评论