用户变动撤销所有刷新token,立即失效accesstoken

This commit is contained in:
mtvpls
2026-06-17 11:35:46 +08:00
parent 84afb97f9f
commit d7727455dc
9 changed files with 118 additions and 4 deletions
+56
View File
@@ -0,0 +1,56 @@
import type { AuthInfo } from './auth';
const userInvalidBefore = new Map<string, number>();
const deviceInvalidBefore = new Map<string, number>();
function makeDeviceKey(username: string, tokenId: string): string {
return `${username}:${tokenId}`;
}
export function invalidateUserAccessTokens(username: string, invalidatedAt = Date.now()): void {
const current = userInvalidBefore.get(username) || 0;
if (invalidatedAt > current) {
userInvalidBefore.set(username, invalidatedAt);
}
}
export function invalidateDeviceAccessToken(
username: string,
tokenId: string,
invalidatedAt = Date.now()
): void {
const key = makeDeviceKey(username, tokenId);
const current = deviceInvalidBefore.get(key) || 0;
if (invalidatedAt > current) {
deviceInvalidBefore.set(key, invalidatedAt);
}
}
export function isAccessTokenInvalidated(authInfo: AuthInfo | null): boolean {
if (!authInfo?.username || !authInfo.timestamp) {
return false;
}
const userInvalidatedAt = userInvalidBefore.get(authInfo.username);
if (userInvalidatedAt && authInfo.timestamp <= userInvalidatedAt) {
return true;
}
if (authInfo.tokenId) {
const deviceInvalidatedAt = deviceInvalidBefore.get(
makeDeviceKey(authInfo.username, authInfo.tokenId)
);
if (deviceInvalidatedAt && authInfo.timestamp <= deviceInvalidatedAt) {
return true;
}
}
return false;
}
export function getAccessTokenInvalidationState() {
return {
userInvalidBefore,
deviceInvalidBefore,
};
}
+5 -2
View File
@@ -1,5 +1,7 @@
import { NextRequest } from 'next/server';
import { isAccessTokenInvalidated } from './access-token-invalidation';
export type AuthInfo = {
password?: string;
username?: string;
@@ -65,7 +67,7 @@ export function getAuthInfoFromCookie(request: NextRequest): AuthInfo | null {
const headerValue = getAuthTokenFromHeader(authHeader);
const headerAuthInfo = parseAuthInfo(headerValue);
if (headerAuthInfo) {
return headerAuthInfo;
return isAccessTokenInvalidated(headerAuthInfo) ? null : headerAuthInfo;
}
}
@@ -75,7 +77,8 @@ export function getAuthInfoFromCookie(request: NextRequest): AuthInfo | null {
return null;
}
return parseAuthInfo(authCookie.value);
const authInfo = parseAuthInfo(authCookie.value);
return isAccessTokenInvalidated(authInfo) ? null : authInfo;
}
// 从cookie获取认证信息 (客户端使用)