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();
    }
最后修改:2023 年 07 月 25 日
您的赞赏是对我最大的支持。