为什么与jwt-auth进行会话的时间是从登录时间起1小时?

问题描述 投票:0回答:2

在laravel 7后端REST API应用程序中,我使用jwt-auth,但登录时遇到问题我可以在前端工作,但在1小时内出现TOKEN_EXPIRED错误。

1)我尝试将会话时间设置为更大,但失败了。在开发阶段,我需要多花1个小时的课程时间。继续进行直播,我将设置会话时间为30分钟。

2)我希望更大的会话是从登录用户的最后一个请求到后端的1小时,而不是从登录开始的1小时

我在下面实现了刷新方法,但是看起来刷新不起作用...

app / Http / Controllers / API / AuthController.php:

<?php

namespace App\Http\Controllers\API;

use App\library\CheckValueType;
use App\Settings;
use Auth;
use Config;
use DB;
use Validator;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Support\Str;
use App\UserGroup;
use App\Http\Resources\UserCollection;
use Avatar;
use Storage;

class AuthController extends Controller
{

    /**
     * Create a new AuthController instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('jwt.auth', ['except' => ['login', 'register', 'activate']]);
    }

    public function login(Request $request)
    {
        $credentials = $request->only('email', 'password');

        if ($token = $this->guard('api')->attempt($credentials)) {
            $loggedUser = $this->guard('api')->user();

            if ($loggedUser->status != 'A') {
                return response()->json(['error' => 'Unauthorized'], HTTP_RESPONSE_NOT_UNAUTHORIZED);
            }
            $loggedUser->last_logged = Carbon::now(config('app.timezone'));
            $loggedUser->save();

            $userGroupsCount = UserGroup
                ::getByUserId($loggedUser->id)
                ->count();
            if ($userGroupsCount == 0) {
                return response()->json(['error' => 'Unauthorized'], HTTP_RESPONSE_NOT_UNAUTHORIZED);
            }

            return $this->respondWithToken($token);
        }

        return response()->json(['error' => 'Unauthorized'], HTTP_RESPONSE_NOT_UNAUTHORIZED);
    }


    public function me()
    {
        return response()->json($this->guard('api')->user());
    }

    public function logout()
    {
        $this->guard('api')->logout();
        return response()->json(['message' => 'Successfully logged out']);
    }

    public function refresh()
    {
        return $this->respondWithToken($this->guard()->refresh());
    }

    protected function respondWithToken($token)
    {
        $loggedUser = $this->guard()->user();

        $user_avatar_path = 'public/' . User::getUserAvatarPath($loggedUser->id, $loggedUser->avatar);
        $filenameData     = User::setUserAvatarProps($loggedUser->id, $loggedUser->avatar, true);
        $usersGroups = User::getUserGroupByUserId($loggedUser->id, false);

        return response()->json([
            'access_token'     => $token,
            'user'             => $loggedUser,
            'token_type'       => 'bearer',
            'user_avatar_path' => $user_avatar_path,
            'filenameData'     => $filenameData,
            'usersGroups'      => $usersGroups,
            'expires_in'       => $this->guard('api')->factory()->getTTL() * 999360 // I SET VERY BIG VALUE
        ]);
    }

    public function guard()
    {
        return \Auth::Guard('api');
    }

在/config/auth.php中:

<?php

return [


    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
    ],

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 99360, // I SET BIG VALUE
            'throttle' => 98860,
        ],
    ],


    'password_timeout' => 10800,  // I SET BIG VALUE

在app / Exceptions / Handler.php中,我拥有:

public function render($request, Throwable $exception)
{

    if ($exception instanceof UnauthorizedHttpException) {
        if ($exception->getPrevious() instanceof TokenExpiredException) {
            \Log::info( '-2 UnauthorizedHttpException TokenExpiredException::' ); // I SEE THIS ERROR LOGGED
            return response()->json(['error' => 'TOKEN_EXPIRED'], $exception->getStatusCode());

我有:

"laravel/framework": "^7.0",
"tymon/jwt-auth": "^1.0.0",

我的配置有什么问题?

MODIFIED:

我添加了文件带有内容和1行错误记录的app / Http / Middleware / JwtMiddleware.php:

<?php

namespace App\Http\Middleware;

use Closure;
use Tymon\JWTAuth\Exceptions\JWTException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;

class JwtMiddleware extends BaseMiddleware
{
    public function handle($request, Closure $next)
    {
        try {
            if (! $user = $this->auth->parseToken()->authenticate()) {
                return response()->json(['success' => false, 'error' => __('Invalid User.')]);
            }
        } catch (TokenExpiredException $e) {
            try {
                $refreshed = $this->auth->refresh($this->auth->getToken());
                $user = $this->auth->setToken($refreshed)->toUser();
                header('Authorization: Bearer ' . $refreshed);
            } catch (JWTException $e) {
                return response()->json(['success' => false, 'error' => __('Could not generate refresh token')]);
            }
        } catch (JWTException $e) {
            \Log::info( '-1 JwtMiddleware$e->getMessage() ::' . print_r(  $e->getMessage(), true  ) );

            return response()->json(['success' => false, 'error' => __('Invalid request')]);
        }

        return  $next($request);
    }
}

并且我添加了文件app / Http / Kernel.php:

   ...
    protected $middleware = [
        \Fruitcake\Cors\HandleCors::class,
        \App\Http\Middleware\TrustProxies::class,
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \App\Http\Middleware\JwtMiddleware::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class
    ];
   ...

and running the page site is broken and I see lines in log :
[2020-05-27 17:08:33] local.INFO: -1 JwtMiddleware$e->getMessage() ::The token could not be parsed from the request  
[2020-05-27 17:08:33] local.INFO: -1 JwtMiddleware$e->getMessage() ::The token could not be parsed from the request  
[2020-05-27 17:08:33] local.INFO: -1 JwtMiddleware$e->getMessage() ::The token could not be parsed from the request  

与app / Http / Controllers / API / AuthController.php的代码有冲突吗?如何解决?

已修改#2:谢谢 !我修复了错误,并在.env中添加了行:

JWT_TTL=20 # 20 minutes
JWT_REFRESH_TTL=20160 # 2 weeks

并清除缓存,我再次登录,因此在我做的应用程序中工作不会注销任何20分钟,但是当我离开该应用程序而未使用该应用程序时在30分钟左右的时间内,我可以按照预期的那样继续工作,而无需登录。还有其他选择吗?

已修改#3:在我的vuejs文件的客户端部分,我在src / App.vue中添加了一个请求拦截器:

created() {
    let self = this
    this.$http.interceptors.response.use(undefined, function (error) {

        return new Promise(function (/*resolve, reject*/) {
            if (typeof error.response.status !== 'undefined' && error.response.status === 401) {
                self.$store.dispatch('logout')  // DEBUGGING
                self.showPopupMessage('Access', 'Not authorized !', 'warn')
                let splitted0 = self.getSplitted(error.response.config.url, '/login', 0)

                if (splitted0 == '') { // not move from login page
                    self.$router.push('/login')   // DEBUGGING
                }
            }

            if (typeof error.response.status !== 'undefined') {
                if (error.response.status === 401) {
                    self.$store.dispatch('logout') // DEBUGGING
                    self.showPopupMessage('Access', 'Not authorized !', 'warn')
                    self.$router.push('/login')  // DEBUGGING
                }
            }

            throw error
        })
    })


}, //  created() {

我捕获到401错误,想知道是否可以捕获来自服务器的请求

header('Authorization: Bearer ' . $refreshed);

并从$ refreshed写入新的access_token值?但是我怎么能抓到它呢?但是一些特殊的退货请求代码?

谢谢!

laravel jwt-auth
2个回答
1
投票

在您的登录名中尝试此操作

if ($token = $this->guard('api')->attempt($credentials,['exp' => Carbon\Carbon::now()->addHours(2)->timestamp])) {

}

或者您可以在ttl中更改config/jwt

让我知道是否有帮助!


1
投票
  • 您需要添加中间件并检查令牌是否已过期。
  • 如果已过期,请检查生成时间是多少,以检查是否应该生成新令牌。将此视为刷新令牌过期时间。如果您想在没有任何时间验证的情况下生成刷新令牌,则可以跳过此步骤。
  • 现在,如果一切正常,将生成一个新令牌,并根据需要将其发送到标头/正文中,并将其存储在前端应用程序中。
<?php

namespace App\Http\Middleware;

use Closure;
use Tymon\JWTAuth\Exceptions\JWTException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;

class JwtMiddleware extends BaseMiddleware
{
    /**
   * Handle an incoming request.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \Closure  $next
   * @return mixed
   */
    public function handle($request, Closure $next)
    {
        try {
            if (! $user = $this->auth->parseToken()->authenticate()) {
                return response()->json(['success' => false, 'error' => __('Invalid User.')]);
            }
        } catch (TokenExpiredException $e) {
            try {
                $refreshed = $this->auth->refresh($this->auth->getToken());
                $user = $this->auth->setToken($refreshed)->toUser();
                header('Authorization: Bearer ' . $refreshed);
            } catch (JWTException $e) {
                return response()->json(['success' => false, 'error' => __('Could not generate refresh token')]);
            }
        } catch (JWTException $e) {
            return response()->json(['success' => false, 'error' => __('Invalid request')]);
        }

        return  $next($request);
    }
}

更新:

这是我在最近的Ionic / Angular APP中遵循的方法。而且效果很好。我以前有做过很多方法,但是很难解释,如果您在以后遇到任何问题,请告诉我。

  • 当您成功登录并将这两个令牌发送到您的前端APP并将其保存在本地存储中时,会同时生成令牌和refresh_token。
  • 对于所有受保护的API,您现在必须发送令牌和refresh_token。
  • 在API端,请验证令牌,如果已过期,请检查refresh_token是否有效或已过期。如果过期,您将注销。
  • 如果refresh_token有效,则生成一个新令牌和refresh_token并将其发送到前端并存储在前端。
  • 此方法存在一个问题,只要用户正在使用APP,登录会话就应该处于活动状态。因此,假设您的JWT_REFRESH_TTL为1天,并且用户在24小时之前使用,它将在24小时之前使用,但由于令牌和refresh_token都将过期,因此仅在1分钟后将无法使用。
  • 为了解决这个问题,您可以为每个API请求生成一个新的refresh_token并在您的前端中对其进行更新。

通常,JWT_TTL应该非常短,例如大约5分钟,而JWT_​​REFRESH_TTL应该是会话活动时间。

© www.soinside.com 2019 - 2024. All rights reserved.