JWT
- 安装 tymon/jwt-auth 扩展包
- 如果您正在使用 Laravel 5.5 或以上版本,请运行以下命令来获取 dev-develop 版本的 JWT 包:
composer require tymon/jwt-auth:dev-develop --prefer-source
- 如果您正在使用 Laravel 5.4 或以下版本,那么要运行下面这条命令:
composer require tymon/jwt-auth
- 对于 Laravel 版本 低于 5.5 的应用,您还要在 config/app.php 文件中设置服务提供者和别名
'providers' => [
....
Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
....
],
'aliases' => [
....
'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
....
],
- 发布配置文件
- 对于 5.5 或以上版本 的 Laravel,请使用下面这条命令来发布配置文件:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
- 对于之前 之前版本的 Laravel,那么应该运行下面这条命令:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
- ==上面的命令会生成 config/jwt.php ==配置文件====
- 生成 JWT 密钥
- JWT 令牌通过一个加密的密钥来签发。对于 Laravel 5.5 或以上版本,运行下面的命令来生成密钥以便用于签发令牌。
php artisan jwt:secret
- Laravel 版本低于 5.5 的则运行
php artisan jwt:generate
- 注册中间件
- JWT 认证扩展包附带了允许我们使用的中间件。在 app/Http/Kernel.php 中注册 auth.jwt 中间件:
protected $routeMiddleware = [
....
'auth.jwt' => \Tymon\JWTAuth\Http\Middleware\Authenticate::class,
];
- 这个中间件会通过检查请求中附带的令牌来校验用户的认证。如果用户未认证,这个中间件会==抛出 UnauthorizedHttpException 异常==。
- 设置路由
- 在 routes/api.php 中添加路由
Route::group(['middleware' => 'auth.jwt'], function () {
Route::get('logout', 'ApiController@logout');
Route::get('user', 'ApiController@getAuthUser'); //在此添加的路由都需要带上token
});
- 更新 User 模型
- JWT 需要在 User 模型中实现 TymonJWTAuthContractsJWTSubject 接口。 此接口需要实现两个方法 getJWTIdentifier 和 getJWTCustomClaims。使用以下内容更新 app/User.php
- ==因为我使用的不是User模型而是自定义的模型,所以需要在config/auth.php中修改默认验证模型==,(这里我driver 如果你路由是api你就在api改,你是用的web就改web)如下:
'providers' => [
'users' => [
'driver' => 'eloquent',
//'model' => App\Models\User::class,
'model' => App\Models\UsersMember::class, //修改为自己用到的模型
],
],
- UsersMember模型中的代码如下:
<?php
namespace App\Models;
use Illuminate\Support\Facades\DB;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class UsersMember extends Authenticatable implements JWTSubject
{
use Notifiable;
/**
* 获取会储存到 jwt 声明中的标识
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* 返回包含要添加到 jwt 声明中的自定义键值对数组
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
- 到上面为止配置完成,下面提供实例代码:
<?php
/**
* 用户登录注册模块
* Created by : PhpStorm
* User: DaPao
* Date: 2021/6/1
* Time: 15:13
*/
namespace App\Http\Controllers;
use App\Entities\Sms;
use App\Models\ReportIssue;
use App\Models\UsersMember;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
class LoginController extends Controller
{
/**
* 短信验证码登录/注册
* @param Request $request
* @return \response\Json
*/
public function loginSms(Request $request)
{
$mobile = $request->mobile;
if(!$mobile ){
return api(config("status.params_fail"),"参数不能为空",[]);
}
//此处有一个"坑",实例化模型new UsersMember取出来的数据不能作为实例传给JWT
$info = UsersMember::where(["mobile"=>$mobile])->select(["mobile","unique_number"])->first();
if(!$info){
$insert = [
"username" => "DaPao",
"password" => bcrypt("123456"),//这里bcrypt加密是因为jwt默认的加密方式是这个,
];
$uid = UsersMember::insertGetId($insert);
if(!$uid){
return api(config("status.error"),"注册用户失败,请重试");
}
//注册成功返回token
//attempt()方法为验证账号密码是否正确,该方法password为必须存在,其他字段该自定义,如此更改password字段,看后面介绍
$token = JWTAuth::attempt(["username"=>"DaPao","password"=>"123456"]);
if(!$token){
return api(config("status.error"),"未知错识,请重试");
}
return api(config("status.success"),"注册成功",["token"=>$token]);
}
//fromUser()方法不需要验证账号密码,为指定实例的用户登录并返回token(注意此处的实际必须得由"169"行静态的方式获得)
$token = JWTAuth::fromUser($info);
return api(config("status.success"),"登录成功",["token"=>$token]);
}
/**
* 账号密码登录
* @param Request $request
* @return \response\Json
*/
public function accountNumberLogin(Request $request)
{
$mobile = $request->mobile;
$password = $request->password;
if(!$mobile || !$password){
return api(config("status.params_fail"),"参数不能为空",[]);
}
$input = [
'mobile' => $mobile,
'password' => $password,
];
$token = JWTAuth::attempt($input);
if(!$token){
return api(config("status.error"),"账号密码错识,请重试",[]);
}
return api(config("status.success"),"登录成功",["token"=>$token]);
}
/**
* 获取登录用户信息
* @param Request $request
* @return \response\Json
*/
public function getUserInfo(Request $request)
{
$token = $request->header('Authorization');
if(!$token){
return api(config("status.params_fail"),"参数不能为空",[]);
}
//authenticate()验证账号密码正确成功则返回登录信息
$user = JWTAuth::authenticate($token);
//格式化用户信息
$info = [
"mobile" => $user->mobile,
"unique_number" => $user->unique_number,
"id" => $user->id,
"nickname" => $user->nickname,
"sex" => $user->sex,
"desc" => $user->desc,
"avatar" => $user->avatar,
];
return api(config("status.success"),"获取成功",['info'=>$info]);
}
/**
* 退出登录
* @param Request $request
* @return \response\Json
*/
public function logout(Request $request)
{
$token = $request->header('Authorization');
if(!$token){
return api(config("status.params_fail"),"参数不能为空",[]);
}
//invalidate()方法使令牌失效
$out = JWTAuth::invalidate($request->token);
if($out){
return api(config("status.success"),"退出成功",[]);
}
return api(config("status.error"),"未知错误,请重试",[]);
}
}
- 最后
- token建议加在header中,因为在https情况下更安全:Authorization:Bearer 你的token
- attempt()方法如果不想使用默认的password字段可在UsersMember模型中添加如下代码:
/**
* 自定义用户名, 即不使用默认的电子邮件认证
*
* @return string
*/
public function username() {
return 'login_name'; // 我的表用户名,原内容为:username
}
public function password() {
return 'credential'; // 我的表用户名,原内容为:password
}
/**
* 自定义的密码字段, 无此,对于密码字段名不为password的登录时将出现密码不存在
* @return string
*/
public function getAuthPassword() {
return $this->credential; // 一定要返回加密了的密码
}
public function getAccountInfoByName( $sName )
{
return $this->where('login_name',$sName)->first();
}