replace database session with redis #3073
Answered
by
beerose
StringKe
asked this question in
Show and tell
-
yarn add ioredis
yarn add @types/ioredis -D
yarn add dayjs // calc time lib server/redis.ts import IoRedis from "ioredis";
import {SessionConfig} from "next/dist/shared/lib/utils";
import {PublicData, SessionModel, simpleRolesIsAuthorized} from "blitz";
import dayjs from "dayjs";
const dbs: Record<string, IoRedis.Redis | undefined> = {
default: undefined,
auth: undefined
};
export function getRedis(): IoRedis.Redis {
if (dbs.default) {
return dbs.default;
}
return dbs.default = createRedis(0);
}
export function getAuthRedis(): IoRedis.Redis {
if (dbs.auth) {
return dbs.auth;
}
return dbs.auth = createRedis(1);
}
export function createRedis(db: number) {
return new IoRedis({
port: 6379,
host: "localhost",
keepAlive: 60,
keyPrefix: 'auth:',
db,
});
}
export const RedisSession: SessionConfig = {
isAuthorized: simpleRolesIsAuthorized,
createSession(session: SessionModel): Promise<SessionModel> {
const expSec = dayjs(session.expiresAt ?? new Date()).diff(new Date(), "second");
return new Promise<SessionModel>((resolve, reject) => {
getAuthRedis().set(`token:${session.handle}`, JSON.stringify(session), "EX", expSec, (err) => {
if (err) {
reject(err);
} else {
getAuthRedis().lpush(`device:${String(session.userId)}`, session.handle)
resolve(session);
}
});
})
},
deleteSession(handle: string): Promise<SessionModel> {
return new Promise<SessionModel>((resolve, reject) => {
getAuthRedis().get(`token:${handle}`).then(result => {
if (result) {
const session = JSON.parse(result) as SessionModel;
const userId = session.userId as unknown as string;
getAuthRedis().lrem(userId, 0, handle).catch(reject);
}
getAuthRedis().del(handle, (err) => {
if (err) {
reject(err);
} else {
resolve({handle});
}
});
})
})
},
getSession(handle: string): Promise<SessionModel | null> {
return new Promise<SessionModel | null>((resolve, reject) => {
getAuthRedis().get(`token:${handle}`).then((data: string | null) => {
if (data) {
resolve(JSON.parse(data));
} else {
resolve(null);
}
}).catch(reject);
});
},
getSessions(userId: PublicData["userId"]): Promise<SessionModel[]> {
return new Promise<SessionModel[]>((resolve, reject) => {
getAuthRedis().lrange(`device:${String(userId)}`, 0, -1).then(result => {
if (result) {
resolve(result.map(handle => {
return this.getSession(handle);
}));
} else {
resolve([]);
}
}).catch(reject);
});
},
updateSession(handle: string, session: Partial<SessionModel>): Promise<SessionModel> {
return new Promise<SessionModel>((resolve, reject) => {
getAuthRedis().get(`token:${handle}`).then(result => {
if (result) {
const oldSession = JSON.parse(result) as SessionModel;
const merge = Object.assign(oldSession, session);
getAuthRedis().set(`token:${handle}`, JSON.stringify(merge)).catch(reject);
}
reject(new Error("cant update session"));
})
})
}
} change blitz.config.ts import {BlitzConfig, sessionMiddleware} from "blitz"
import {RedisSession} from "./serve/redis";
const config: BlitzConfig = {
middleware: [
sessionMiddleware({
cookiePrefix: "design",
...RedisSession
}),
],
// Uncomment this to customize the webpack config
webpack: (config, {buildId, dev, isServer, defaultLoaders, webpack}) => {
return config
},
}
module.exports = config |
Beta Was this translation helpful? Give feedback.
Answered by
beerose
Dec 20, 2021
Replies: 1 comment
-
Nice! Thanks for sharing @StringKe |
Beta Was this translation helpful? Give feedback.
0 replies
Answer selected by
StringKe
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice! Thanks for sharing @StringKe