登陆需要的用户表:php artisan make:migration create_admins_table --create=admins
运行后在database/migrations下生成2022_06_15_032902_create_admins_table.php文件,内容如下:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateAdminsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('admins', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('phone')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('admins');
}
}
1.安装 Jwt-auth 扩展包。
composer require tymon/jwt-auth
2.安装完成后在配置文件config/app.php 中注册服务提供者和别名
'providers' => [
...
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
]
3.发布资源和配置,在config目录下会生成jwt.php配置文件
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
4.生成密钥,在.env文件中可以看到新增JWT_SECRET=secret
$ php artisan jwt:secret
5.配置Auth.php,在config/auth.php文件中,将guards/driver更新为jwt
可配置多个,后续认证通过auth(‘api’) 或auth(‘admin’)区分,
model标识:登陆所用的表
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
'admin' => [
'driver' => 'jwt',
'provider' => 'admins',
'hash' => false,
],
...
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
],
6.修改model,使用jwt-auth作为用户认证,则需要修改User模型。在app/Admin.php
getJWTCustomClaims() 该方法可以将数据注入token中。
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class Admin 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',
];
public function getJWTIdentifier()
{
// TODO: Implement getJWTIdentifier() method.
return $this->getKey();
}
public function getJWTCustomClaims()
{
// TODO: Implement getJWTCustomClaims() method.
// return [];/*不添加数据*/
$data = Crypt::encryptString(
json_encode(
array('phone'=>$this->phone,'name' => $this->name),
JSON_UNESCAPED_UNICODE
)
);
return compact('data');
}
}
7.自定义认证中间件
php artisan make:middleware RefreshToken
运行后,会在app/http/middleware中看到RefreshToken.php文件,需要注意的是记得在app/http/Kernel.php添加如下代码:
protected $routeMiddleware = [
...
'refreshtoken' => \App\Http\Middleware\RefreshToken::class,
];
RefreshToken.php中间件代码如下:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
class RefreshToken extends BaseMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// 检查此次请求中是否带有 token,如果没有则抛出异常。
$this->checkForToken($request);
// 使用 try 包裹,以捕捉 token 过期所抛出的 TokenExpiredException 异常
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::guard('admin')->onceUsingId($this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']);
} catch (JWTException $exception) {
// 如果捕获到此异常,即代表 refresh 也过期了,用户无法刷新令牌,需要重新登录。
throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage());
}
}
// 在响应头中返回新的 token
return $this->setAuthenticationHeader($next($request), $token);
//return $next($request);
}
}
8.使用jwt
8.1创建控制器
php artisan make:controller V2\AuthController
在app/http/controllers下,修改代码,如下:
<?php
namespace App\Http\Controllers\V2;
use App\Http\Controllers\Controller;
use App\Admin;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
class AdminAuthController extends Controller
{
//用户注册
public function register(Request $request){
$valid = Validator::make($request->all(), [
'name' => 'required|string|unique:admins',
'phone' => 'required|unique:admins',
'password' => 'required|string|min:6|max:10',
]);
if ($valid->fails()) {
return array(
'code' => 1,
'message' => $valid->errors()->first(),
'data' => []
);
}
$user = new Admin();
$user->name = $request->name;
$user->phone = $request->phone;
$user->password = bcrypt($request->password);
$user->save(); //插入数据库,创建用户
return $user;
}
//用户登录
public function login(Request $request){
$credentials = $request->only('phone', 'password');
if (! $token = auth('admin')->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
//return auth('api')->user(); //此处可以获取登录成功用户的信息,如账号,邮箱等
return $this->respondWithToken($token);
}
/**
* 退出登录
* @return \Illuminate\Http\JsonResponse
*/
public function logout(){
auth('admin')->logout();
return response()->json(['message' => '退出成功!']);
}
/**
* 获取用户信息
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function user()
{
$user = Admin::find(Auth::user()->id);
return response([
'status' => 'success',
'data' => $user
]);
}
/**
* Refresh a token.
* 刷新token,如果开启黑名单,以前的token便会失效。
* 值得注意的是用上面的getToken再获取一次Token并不算做刷新,两次获得的Token是并行的,即两个都可用。
* @return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
return $this->respondWithToken(auth('admin')->refresh());
}
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
]);
}
}
8.2编写路由routes/api.php
Route::group(['prefix'=>'v2','namespace'=>'V2'],function ($r) {//第二版本
$r->get('register','AdminAuthController@register'); //注册
$r->post('login','AdminAuthController@login'); //登录
$r->post('logout', 'AdminAuthController@logout');// 退出
Route::middleware(['refreshtoken','jwt.auth'])->group(function($router) {
//访问地址 api/v1/auth/user
$router->get('auth/user', 'AdminAuthController@user');
$router->get('auth/refresh', 'AdminAuthController@refresh');
});
});
测试流程:**先注册、登陆时获取token,在通过token请求其他需要鉴权的接口。**