资讯专栏INFORMATION COLUMN

API 开发中可选择传递 token 接口遇到的一个坑

siberiawolf / 1083人阅读

摘要:此处做刷新处理具体代码可以参考必须需要登录验证的接口在响应头中返回新的问题解决。

在做 API 开发时,不可避免会涉及到登录验证,我使用的是jwt-auth

在登录中会经常遇到一个token过期的问题,在config/jwt.php默认设置中,这个过期时间是一个小时,不过为了安全也可以设置更小一点,我设置了为五分钟。

五分钟过期,如果就让用户去登录,这种体验会让用户直接抛弃你的网站,所以这就会使用到刷新token这个功能

正常情况下是写一个刷新token的接口,当过期的时候前端把过期的token带上请求这个接口换取新的token

不过为了方便前端也可以使用后端刷新返回,直至不可刷新,我用的就是这个方法:使用 Jwt-Auth 实现 API 用户认证以及无痛刷新访问令牌

而坑就是这样来的,

在必须需要登录验证的接口设置刷新token

checkForToken($request);

        try {
            /****************************************
             * 尝试通过 tokne 登录,如果正常,就获取到用户
             * 无法正确的登录,抛出 token 异常
             ****************************************/
            if ($this->auth->parseToken()->authenticate()) {
                return $next($request);
            }
            throw new UnauthorizedHttpException("jwt-auth", "User not found");

        } catch (TokenExpiredException $e) {
            try {
                /****************************************
                 * token 过期的异常,尝试刷新 token
                 * 使用 id 一次性登录以保证此次请求的成功
                 ****************************************/
                $token = $this->auth->refresh();
                $id = $this->auth
                    ->manager()
                    ->getPayloadFactory()
                    ->buildClaimsCollection()
                    ->toPlainArray()["sub"];

                auth()->onceUsingId($id);
            } catch (JWTException $e) {
                /****************************************
                 * 如果捕获到此异常,即代表 refresh 也过期了,
                 * 用户无法刷新令牌,需要重新登录。
                 ****************************************/
                throw new UnauthorizedHttpException("jwt-auth", $e->getMessage(), null, StatusServe::HTTP_PAYMENT_REQUIRED);
            }
        }

        // 在响应头中返回新的 token
        return $this->setAuthenticationHeader($next($request), $token);
    }
}

而有些页面,比如文章列表页面,这个接口登录与不登录皆可访问,不过登录的时候可以在页面上显示是否点赞了这篇文章。所以这个接口直接使用的是jwt-auth默认的option中间件


 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace TymonJWTAuthHttpMiddleware;

use Closure;
use Exception;

class Check extends BaseMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  IlluminateHttpRequest  $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);
    }
}

一开始也没有发现问题,直到测试的时候,发现文章列表页面点赞过的文章,过了一段时间再刷新的时候发现不显示已点赞,但是进入个人中心的已点赞文章可以看到。

刚开始测试没找出原因,直接暴力调试代码,发现没获取到登录用户,一想不对呀,已经传token为何获取不到。经过发现,去到个人中心,再回到新闻列表页就可以正常显示,过了一段时间又不显示了。

经过这一轮之后,大概明白,在新闻列表页时,token已经过期,但是当时图方便用的jwt-auth默认的中间件,不会刷新token,所以这个接口获取不到登录的用户。当进入个人中心,发现当前token已经过期,后台刷新token返回,这时候再回到文章列表页就可以得到正常的数据,一段时间后,token又失效了,所以有无法看到点赞过的文章

解决方法,自己写一个option中间件,当存在token的时候,也需要做token刷新处理。

auth->parser()->setRequest($request)->hasToken()) {
            try {
                $this->auth->parseToken()->authenticate();
            } catch (TokenExpiredException $e) {
                // 此处做刷新 token 处理
                // 具体代码可以参考必须需要登录验证的接口
                // 在响应头中返回新的 token
                return $this->setAuthenticationHeader($next($request), $token);
            } catch (Exception $e) {
            
            }

        }

        return $next($request);
    }
}

问题解决。
最后说一个并发会出现的问题:

# 当前 token_1 过期,先发起 a 请求,之后马上发起 b 请求
# a 请求到服务器,服务器判断过期,刷新 token_1
# 之后返回 token_2 给 a 请求响应
# 这时候迟一点的 b 请求用的还是 token_1 
# 服务器已经将此 token_1 加入黑名单,所以 b 请求无效
       token_1         刷新返回 token_2
a 请求 --------> server -------> 成功
       token_1         过期的 token_1,应该使用 token_2
b 请求 --------> server ------> 失败

jwt-auth已经想到这种情况,我们只需要设置一个黑名单宽限时间即可

我设置为5秒,就是当token_1过期了,你还能继续使用token_1操作5秒时间

原文地址

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/28900.html

相关文章

  • 使用 vue2.0 开发微信公众号下前后端分离SPA站点之旅

    摘要:目前正在写一个微信公众号的小项目,记录一下遇到的问题和解决方法主要是前端。前端提交时使用,在后端再取出对应的微信支付看了下文档,以前是需要用唤起支付,而现在则是把微信内置到了微信的浏览器中。 目前正在写一个微信公众号的小项目,记录一下遇到的问题和解决方法(主要是前端)。内容持续更新中~ 主要实现 前后端分离前端为 SPA 单页面使用微信的JSSDK微信支付 技术方案 后端使用 php ...

    afishhhhh 评论0 收藏0
  • 使用 vue2.0 开发微信公众号下前后端分离SPA站点之旅

    摘要:目前正在写一个微信公众号的小项目,记录一下遇到的问题和解决方法主要是前端。前端提交时使用,在后端再取出对应的微信支付看了下文档,以前是需要用唤起支付,而现在则是把微信内置到了微信的浏览器中。 目前正在写一个微信公众号的小项目,记录一下遇到的问题和解决方法(主要是前端)。内容持续更新中~ 主要实现 前后端分离前端为 SPA 单页面使用微信的JSSDK微信支付 技术方案 后端使用 php ...

    Taonce 评论0 收藏0
  • thinkphp3.2,微信JS-SDK开发过程中遇到各种问题与细节分享

    摘要:备注登录后可在开发者中心查看对应的接口权限。下载官网提供的示例代码,参照中的代码一步一步来实现。否则分享后的页面会签名失败返回的与分享的是否一致 首先完成官方文档前两步(很好理解就不具体说了):步骤一:绑定域名先登录微信公众平台进入公众号设置的功能设置里填写JS接口安全域名。备注:登录后可在开发者中心查看对应的接口权限。步骤二:引入JS文件在需要调用JS接口的页面引入如下JS文件,(支...

    miya 评论0 收藏0
  • 分享一下这两周爬微信支付~希望有借鉴作用(PHP)

    摘要:这个坑就是要注意回调结束要返回成功的响应这几天做微信支付暂时遇到的问题就这么多,只能说注意细节吧,爬过的坑记录下来以后遇到就懂处理了。 前言 其实任何接口开发只要按照给出来的接口文档和例子开发基本上不会有太大问题的,一些问题都是出在杂七杂八的小细节上,现在分享一下微信支付开发中自己遇到的小细节。按照文档做完开发前配置,比如JS安全域名配置、网页授权域名、公众号授权目录等等... 坑一:...

    Tangpj 评论0 收藏0
  • node微信后台开发初探

    摘要:今天看到了微信官方推出的一个浏览器插件,用来调试微信后台和页面的,挺好的。这个是根据别人的文章总结的,时间戳随机数生成签名将三者进行加密与签名进行对比之后每次都会进行身份校验。然而后面还有更深的坑。 原文摸索中遇到的一些坑,虽然很简单,但新手还是会被坑到,就稍微记录一下吧,也当学习手册,最好去了解一下express,不是很难,这边只是简单的配置,更高级的接口还是去看文档,模块或者自己实...

    mingzhong 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<