- When doing API development, login authentication is inevitably involved, and I use JwT-Auth
- You’ll often come across one during loginstokenExpired issues, in
config/jwt.php
By default, the expiration time is one hour, but it can be lower for security purposes, so I set it to five minutes. - After five minutes, if you let the user log in, this experience will cause the user to abandon your site directly, so this will use the refresh token function
- In normal cases, an interface is written to refresh the token. When the token expires, the front-end brings the expired token to the interface and requests the new token
- But to make it easier for the front end to use the back-end refresh back until it is no longer refreshed, I used this method: API user authentication using JwT-Auth and painlessly refreshing access tokens
- And that’s how you get pits,
- Set the refresh token on the interface that must require login authentication
<? php namespace App\Http\Middleware; use App\Services\StatusServe; use Closure; use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Exceptions\TokenExpiredException; use Tymon\JWTAuth\Http\Middleware\BaseMiddleware; The class CheckUserLoginAndRefreshToken extends BaseMiddleware {/ * * * to check the user login, user login normally, If the token expires * refresh the token from the response header returns * * @param$request
* @param Closure $next
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response
* @throws JWTException
*/
public function handle($request, Closure $next) {/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * check whether the token is there * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /$this->checkForToken($request); Try {/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * try through tokne login, if normal, is access to the user * cannot correct login, Throw a token abnormal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /if ($this->auth->parseToken()->authenticate()) {
return $next($request);
}
throw new UnauthorizedHttpException('jwt-auth'.'User not found');
} catch (TokenExpiredException $e) {try {/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * token expired abnormalities, Try to refresh token * disposable id login to ensure the success of the request * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /$token = $this->auth->refresh();
$id = $this->auth
->manager()
->getPayloadFactory()
->buildClaimsCollection()
->toPlainArray()['sub'];
auth()->onceUsingId($id);
} catch (JWTException $e) {/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * if catch this exception, which stands for the refresh is expired, * users cannot refresh token, you need to log in. ****************************************/ throw new UnauthorizedHttpException('jwt-auth'.$e->getMessage(), null, StatusServe::HTTP_PAYMENT_REQUIRED); }} // Return the new token in the response headerreturn $this->setAuthenticationHeader($next($request), $token); }}Copy the code
- For some pages, such as the article list page, this interface can be accessed with or without login, but when logging in, the page can display whether the article is liked or not. So this interface directly uses the default option middleware of JWT-Auth
<? php /* * This file is part of jwt-auth. * * (c) Sean Tymon <[email protected]> * * For the full copyright and license information, please view the LICENSE * file that was distributed with thissource code.
*/
namespace Tymon\JWTAuth\Http\Middleware;
use Closure;
use Exception;
class Check extends BaseMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->parser()->setRequest($request)->hasToken()) {
try {
$this->auth->parseToken()->authenticate();
} catch (Exception $e) {}}return $next($request); }}Copy the code
- No problem was found at the beginning, until the test, I found that the “liked” articles on the article list page were not displayed when I refreshed them after a period of time, but the “liked” articles in the personal center could be seen.
- At the beginning of the test, I did not find out the reason, but directly debugging the code by force. I found that I did not get the login user. After discovery, go to the personal center, and then return to the news list page can be displayed normally, after a period of time does not show again.
- After this round, it is probably understood that the token has expired at the time of the news list page, but the default middleware of jWT-Auth, which is convenient at that time, does not refresh the token, so the interface does not get the logged-in user. When you enter the personal center and find that the current token has expired, the background refreshes the token and returns. At this time, you can return to the article list page and get the normal data. After a period of time, the token is invalid again, so you can’t see the articles that have been liked
- To solve this problem, write an Option middleware by yourself. When tokens exist, you need to refresh them.
<? php namespace App\Http\Middleware; use Closure; use Exception; class Check extends BaseMiddleware { publicfunction handle($request, Closure $next)
{
if ($this->auth->parser()->setRequest($request)->hasToken()) {
try {
$this->auth->parseToken()->authenticate();
} catch (TokenExpiredException $e// Return a new token in the response headerreturn $this->setAuthenticationHeader($next($request), $token);
} catch (Exception $e) {}}return $next($request); }}Copy the code
Problem solved. One last problem with concurrency:
Token_1 (toKEN_1) : token_1 (token_1) : token_1 (token_1) : token_1 (token_1) : token_1 (token_1) : token_1 (token_1) : token_1 (token_1) Update toKEN_1 # and return token_2 to request A in response to token_1 # A request --------> server -------> Success TOKEN_1 expired token_1, The request --------> server ------> failed using token_2bCopy the code
Jwt-auth has already thought of this situation, we just need to set a blacklist grace period
5
token_1
token_1
5
The original address