如何正确使用Directus的/auth/refresh接口实现访问令牌刷新
问题解决方案
1. 问题根源&缺失的配置
- Directus原生完全支持用有效期内的refresh_token兑换新的access_token,不受旧access_token是否过期影响,你遇到的报错核心原因是全局请求拦截器给刷新令牌的请求也附加了已过期的Authorization头,Directus在校验到请求头里的过期access_token时会直接返回401,不会走到refresh_token的校验逻辑。
- 你需要给拦截器添加接口白名单,登录、刷新令牌这两个接口不要附加Authorization头:
Angular拦截器核心逻辑示例:intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { // 白名单接口:不需要加Authorization头 const whiteList = ['/auth/login', '/auth/refresh']; if (whiteList.some(url => request.url.includes(url))) { return next.handle(request); } // 其他请求附加令牌 const token = localStorage.getItem('access_token'); if (token) { request = request.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); } return next.handle(request); } - 额外检查项:刷新请求的参数是否正确
- REST请求:POST到
/auth/refresh,请求体只需要传{"refresh_token": "你本地存储的refresh_token"},不需要其他参数 - GraphQL mutation:不需要带Authorization头,请求格式为:
mutation RefreshToken($refreshToken: String!) { auth_refresh(refresh_token: $refreshToken) { access_token refresh_token expires } } - REST请求:POST到
2. 保持登录功能实现方案
不需要额外开发冗余的身份验证逻辑,按以下流程配置即可:
- 登录时判断用户是否勾选「保持登录」,勾选则把
access_token、refresh_token存在localStorage,未勾选则存在sessionStorage(关闭浏览器自动清除) - 拦截器捕获到普通业务请求返回401时,先暂停所有 pending 的请求,调用刷新令牌接口,拿到新的令牌后替换本地存储的内容,再重放之前失败的请求
- 如果刷新令牌接口也返回401,说明refresh_token已经过期,直接清空本地存储的令牌,跳转到登录页即可
2b. refresh_token长有效期的设计原因
这是OAuth2的标准设计逻辑:
access_token每次业务请求都会携带,泄露风险更高,设置15分钟的短有效期可以降低令牌泄露后的危害范围refresh_token仅在刷新令牌时才会发送给服务端,传输频次极低泄露风险小,设置7天长有效期是为了避免用户频繁登录,提升使用体验
3. 权限相关猜测的澄清
该问题和directus_sessions表的权限完全无关,刷新令牌是Directus内置的系统公开接口,校验逻辑走内部能力,不需要给public角色开放任何directus_sessions表的权限,不需要做额外的权限配置。
内容的提问来源于stack exchange,提问作者DerSkillBaumApfel
相关产品推荐
相关产品推荐

