搭建个人知识付费应用系统-(2)用户|搭建个人知识付费应用系统-(2)用户 Session 管理
视频地址: https://www.bilibili.com/vide...
用户管理
graph TBStart1([Start])-->
logout1[注销] --> check1{判断 url 参数} --F--> destroySession[清除 Session 然后 SSO 注销] -->logout1
check1 --T--> logout2[跳转 SSO 注销链接]
logout2-->Stop1([Stop])Start2([Start]) --登录回调--> callback[记录 Session] --> redierct[跳回页面] --> loader[Loader 读取用户信息] --> check2{是否失效} --F--> getUserInfo[获取用户信息] --> Stop2([Stop])
check2 --T--> refreshToken[通过 refreshToken 更新 accessToken] --> getUserInfo
Session 管理
SessionStorage
import { createCookieSessionStorage } from '@remix-run/node';
export const sessionStorage = createCookieSessionStorage({
cookie: {
name: '_session',
sameSite: 'lax',
path: '/',
httpOnly: true,
secrets: [process.env.COOKIE_SECRET || 's3cr3t'],
secure: process.env.NODE_ENV === 'production'
}
});
export const { getSession, commitSession, destroySession } = sessionStorage;
Token 管理
将 code 换 AccessToken 和 RefreshToken 换 AccessToken 两个方法封装
async function tokenRequest(body) {
const formBody = [];
// eslint-disable-next-line
for (const property in body) {
const encodedKey = encodeURIComponent(property);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const encodedValue = https://www.it610.com/article/encodeURIComponent(body[property]);
formBody.push(`${encodedKey}=${encodedValue}`);
}
const res = await fetch(`${process.env.AUTHING_APP_DOMAIN}/oidc/token`, {
method:'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;
charset=UTF-8'
},
body: formBody.join('&')
});
const oidcToken = (await res.json()) as OidcResponse;
return oidcToken;
}export function code2Token(code: string) {
const body = {
client_id: process.env.AUTHING_APP_ID,
client_secret: process.env.AUTHING_APP_SECRET,
grant_type: 'authorization_code',
code
};
return tokenRequest(body);
}export function refreshToken(token: OidcResponse) {
const body = {
client_id: process.env.AUTHING_APP_ID,
client_secret: process.env.AUTHING_APP_SECRET,
grant_type: 'refresh_token',
refresh_token: token.refresh_token
};
return tokenRequest(body);
}
i18n 【搭建个人知识付费应用系统-(2)用户|搭建个人知识付费应用系统-(2)用户 Session 管理】插件: https://remix-i18n.js.cool
安装
npm install --save remix-i18n
配置
export interface RemixI18nOptions {
// 支持的语言
supportedLanguages: string[];
// 失败备选
fallbackLng: string;
}
const i18n = new RemixI18n({
supportedLanguages: ['en', 'tl', 'da', 'zh'],
fallbackLng: 'zh'
});
添加语言翻译
i18n.set('locale', {
hello: '你好'
});
客户端设置
// entry.client.tsx
import { hydrate } from 'react-dom';
import { RemixBrowser } from 'remix';
import { I18nProvider } from 'remix-i18n';
import { i18n, getLocale } from '~/i18n';
const locale = getLocale(window.location.pathname);
i18n.locale(locale);
hydrate(
,
document
);
服务器端设置
// entry.server.tsx
import { renderToString } from 'react-dom/server';
import { RemixServer } from 'remix';
import type { EntryContext } from 'remix';
import { I18nProvider } from 'remix-i18n';
import { i18n, getLocale } from '~/i18n';
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const locale = getLocale(new URL(request.url).pathname);
i18n.locale(locale);
const markup = renderToString(
);
responseHeaders.set('Content-Type', 'text/html');
return new Response(`${markup}`, {
status: responseStatusCode,
headers: responseHeaders
});
}
语言切换
const i18n = useI18n();
const location = useLocation();
useEffect(() => {
const locale = getLocale(location.pathname);
if (locale !== i18n.locale()) {
i18n.locale(locale);
}
}, [location]);
使用模板
const { t } = useI18n();
// jsx
{t('hello')};
P.S. 遗留问题: 用户扩展信息的获取(抽空摸索清楚再继续)
下期主题: DaisyUI 主题切换实现
推荐阅读
- 机器学习基础知识|机器学习之多元线性回归
- 从零搭建 Spring MVC 项目 —— HelloWorld
- 一个人的兵荒马乱
- 从前从前,有个人爱你很久
- 搭建个人知识付费应用系统-(1)框架初始化、用户身份集成
- 酥20190519个人朋友圈的发展历史
- 请给我一片蓝天,一个人,一只狗!
- 企业搭建知识库的重要性,你了解多少()
- 创建知识库使您的客户能够体验自助服务
- 青春旅程·4