JWT 在專案中的實際使用

dividez發表於2018-10-08

關於JWT 可以參考 JWT 完整使用詳解 這裡說一下在實際專案中的使用:

laravel 5.5
php7.1
"tymon/jwt-auth": "1.*@rc"

JWT token 的重新整理 和 基於 JWT 實現單使用者登陸

理解

使用者登陸後 獲取到 tokenA (這個時候 tokenA 的有效期是60分鐘)

透過 tokenA 獲取到 tokenB (這個時候 tokenB 的有效期是60分鐘,tokenA 開始進行 60秒的 倒數計時,60秒後就會被拉黑)

tokenB 換取 tokenC (成功後 tokenB 開始進行60秒倒數計時,60秒後會被拉黑)

env 配置如下:

JWT_SECRET=jbSn01PbHsFoRzEqHtuOsM3rV3FCsGcI
JWT_BLACKLIST_ENABLED=true  # 是否開啟toekn黑名單 生產環境需要開啟 寬限時間需要開啟黑名單(預設是開啟的),黑名單保證過期token不可再用,最好開啟
JWT_BLACKLIST_GRACE_PERIOD=60 # 設定寬限時間,單位:秒
JWT_REFRESH_TTL=20160 # 重新整理時間  單位:分鐘
JWT_TTL=60 # 有效時間  單位:分鐘

基於 JWT token 的單使用者登陸, 在 token 的載荷配置中做一點手腳即可:

<?php

namespace App\Http\Controllers;

use Auth;
use App\Business\UserBusiness;
use App\Transformers\UserTransformer;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Facades\JWTAuth;
use Tymon\JWTAuth\Facades\JWTFactory;

/**
 * 使用者相關
 *
 * @Resource("user", uri="/api")
 */
class UserController extends Controller
{

    protected $userBusiness;

    /**
     * UserController constructor.
     * @param UserBusiness $userBusiness
     */
    public function __construct(UserBusiness $userBusiness)
    {
        $this->userBusiness = $userBusiness;
    }

    /**
     * 使用者登陸
     *
     * 使用 `username` 和 `password` 進行登陸。
     *
     * @Post("/login")
     * @Versions({"v1"})
     * @Transaction({
     *      @Request({"username": "foo", "password": "bar"}),
     *      @Response(200, body={"code":1,"time":"2018-08-10 09:32:44","message":"success","data":{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9hcGkuc21hcnR2aWRlby5jb21cL2FwaVwvbG9naW4iLCJpYXQiOjE1MzM4NjQ3NjQsImV4cCI6MTUzMzg2ODM2NCwibmJmIjoxNTMzODY0NzY0LCJqdGkiOiJsZTJObzRLVDZlT0NyVnZCIiwic3ViIjoiZGVkZjYyZTI5MDA0MTFlODgzM2I1NGVlNzVlNTM1MzciLCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIn0.OdJlE_pUuttqIxsjKF-FAcZOhMYitS69fh18lPZAYmQ","token_type":"bearer","expires_in":3600}}),
     *      @Response(200, body=
     *          {
     *              "message": "使用者不存在",
     *              "code": 4000,
     *              "status_code": 500
     *          }
     *      )
     *
     * })
     */
    public function login(Request $request)
    {
        $rules = [
            'username' => 'required',
            'password' => 'required'
        ];

        $this->_validate($request, $rules);

        $spbill_create_ip = $request->header('x-real-ip')?: $request->ip();

        iLog('----------spbill_create_ip------------'. $spbill_create_ip);

        $username = $request->username;
        $password = $request->password;

        $login_time = time();
        $user = $this->userBusiness->dologin($username,$password,$spbill_create_ip,$login_time);

        // Get the token
        $factory = JWTFactory::customClaims([
            'sub'   => $user->guid,
            'ip' => $spbill_create_ip,
            'login_time' => $login_time
        ]);
        $payload = $factory->make();
        $token = JWTAuth::encode($payload);

        return $this->_response($this->respondWithToken((string)$token));

    }

    protected function respondWithToken($token)
    {
        return [
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => JWTAuth::factory()->getTTL() * 60
        ];
    }
}
<?php

namespace App\Http\Middleware;

use App\Business\ResponseException;
use App\Common\ResponseCode;
use Closure;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;

class ClientCheck extends BaseMiddleware
{
    /**
     * @param $request
     * @param Closure $next
     * @return mixed
     * @throws ResponseException
     */
    public function handle($request, Closure $next)
    {
        $array = $this->auth->payload()->jsonSerialize();

        $user = $this->auth->user();

        if (key_exists('ip',$array) && key_exists('login_time',$array)) {
            if ($array['ip'] != $user->ip || $array['login_time'] != $user->login_at) throw new ResponseException("該賬戶已在其他裝置登陸",ResponseCode::OTHER_CLIENT_LOGIN);
        }
        return $next($request);
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章