自己留个笔记吧,一边搭建一边记录。之前是使用dingo+jwt搭建的Api认证,这次只用jwt。
参考文档:参考jwt的文章 并作修改
Laravel
1. 使用 composer 安装
# 建议使用1.0以上版本
composer require tymon/jwt-auth 1.*@rc
2. 进行一些配置
Providers
config/app.php
中在 providers
里添加
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
Class Aliases
config/app.php
中在 aliases
里添加 两条:
'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
修改认证驱动
修改config/auth.php
,将 api 的 driver 修改为 jwt。如下:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
]
然后发布相应配置文件:
# 这条命令会在 config 下增加一个 jwt.php 的配置文件
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
最后生成密钥:
# 这条命令会在 .env 文件下生成一个加密密钥,如:JWT_SECRET=foobar
php artisan jwt:secret
更新你的模型
如果你使用默认的 User 表来生成 token,你需要在该模型下增加一段代码
<?php
namespace App;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements JWTSubject # 这里别忘了加
{
use Notifiable;
// Rest omitted for brevity
/**
* 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 下,route/api.php
中的路由默认都有前缀 api
。
Route::group([
'prefix' => 'auth'
], function ($router) {
Route::post('login', 'AuthController@login');
Route::post('logout', 'AuthController@logout');
Route::post('refresh', 'AuthController@refresh');
Route::post('me', 'AuthController@me');
});
创建 token 控制器
php artisan make:controller AuthController
并写入:
AuthController
值得注意的是 Laravel 这要用 auth('api')
,但是我用jwt.auth的中间件效果是一样的。
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
class AuthController extends Controller
{
/**
* Create a new AuthController instance.
* 要求附带email和password(数据来源users表)
*
* @return void
*/
public function __construct()
{
// 这里额外注意了:官方文档样例中只除外了『login』
// 这样的结果是,token 只能在有效期以内进行刷新,过期无法刷新
// 如果把 refresh 也放进去,token 即使过期但仍在刷新期以内也可刷新
// 不过刷新一次作废
$this->middleware('auth:api', ['except' => ['login']]);
// 另外关于上面的中间件,官方文档写的是『auth:api』
// 但是我推荐用 『jwt.auth』,效果是一样的,但是有更加丰富的报错信息返回
}
/**
* Get a JWT via given credentials.
*
* @return \Illuminate\Http\JsonResponse
*/
public function login()
{
$credentials = request(['email', 'password']);
if (! $token = auth('api')->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
/**
* Get the authenticated User.
*
* @return \Illuminate\Http\JsonResponse
*/
public function me()
{
return response()->json(auth('api')->user());
}
/**
* Log the user out (Invalidate the token).
*
* @return \Illuminate\Http\JsonResponse
*/
public function logout()
{
auth('api')->logout();
return response()->json(['message' => 'Successfully logged out']);
}
/**
* Refresh a token.
* 刷新token,如果开启黑名单,以前的token便会失效。
* 值得注意的是用上面的getToken再获取一次Token并不算做刷新,两次获得的Token是并行的,即两个都可用。
* @return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
return $this->respondWithToken(auth('api')->refresh());
}
/**
* Get the token array structure.
*
* @param string $token
*
* @return \Illuminate\Http\JsonResponse
*/
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60
]);
}
}
注意:
还要生成users表
创建建表文件
php artisan make:migration create_users_table
生成表
php artisan migrate
AuthController添加注册用户方法register
引入
use Validator;
use App\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Tymon\JWTAuth\Facades\JWTAuth;
Auth控制器添加注册方法
public function register(Request $request)
{
$rules = [
'name' => ['required'],
'email' => ['required'],
'password' => ['required', 'min:6', 'max:16'],
];
$payload = $request->only('name', 'email', 'password');
$validator = \Validator::make($payload, $rules); //或者use引入Validator
// 验证格式
if ($validator->fails()) {
return response()->json(['code'=>401,'msg'=>$validator->errors()]);
}
// 创建用户 创建前可以先查询一下有没有数据以防出现问题,这里没写
$result = User::create([
'name' => $payload['name'],
'email' => $payload['email'],
'password' => bcrypt($payload['password']),
]);
if ($result) {
//自己新增的返回类型
$token = JWTAuth::fromUser($result);
$return = [
'code'=>201,
'msg'=>'创建用户成功',
'data'=>['token'=>$token],
];
return response()->json($return);
} else {
return response()->json([
'code'=>404,
'msg'=>'创建用户失败',
]);
}
}
AuthController添加获取token的方法,
带着账号密码去获取token也相当于是登录了,返回token的地方可以只写在获取token的方法里,这样的话登录注册就可以选择不返回token,都行吧。
public function token(Request $request)
{
$validator = \Validator::make($request->all(), [
'email' => 'required',
'password' => 'required',
]);
if ($validator->fails()) { //或者在基类控制器封装错误方法
return response()->json(['code'=>400,'msg'=>$validator->errors()->first()]);
}
$email = $request->get('email');
$password = $request->get('password');
$secret=env('APP_KEY');
//临时启用
if(strtolower($password) != md5($email.'_'.$secret)){
return response()->json(['code'=>401,'msg'=>'unauthorized']);
}
//$credentials = $request->only('email', 'password');
$credentials = [
['email','=',$email],
];
$user = User::where($credentials)->first();
if(!$user || !$token = JWTAuth::fromUser($user)){
return response()->json(['code'=>401,'msg'=>'unauthorized']);
}
//基于Facade的账号密码参数创建一个新的token,也可以基于辅助函数auth()创建token
$credentials = $request->only('email', 'password');
$token = JWTAuth::attempt($credentials);
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60
]);
}
我的路由
postman调用结果
不足之处
因为写的是demo,所以没有做异常处理,比如register需要查询是否有此用户,否则会报错。
附录:
这样开发出来的接口,假设请求me()方法,而此时token过期了的话因为底层JWTAuth会判断是否过期,这个时候就会报错,因为是底层代码报错,所以你没办法去处理更改。
怎么办呢?
这个时候就需要自定义一个中间件去接管底层的方法实现,可以参考这篇文章:自定义中间件检查token、刷新过期的token