可用资源

  • NPM 包

    • @authing/nextjs:https://github.com/Authing/authing-nextjs
    • @authing/remix: https://github.com/Authing/authing-remix
  • 论坛帮忙

    • Next.js 问题反馈: https://forum.authing.cn/t/topic/601
    • Remix 问题反馈: https://forum.authing.cn/t/topic/602

Authing 用户池配置

该局部基本上大部分框架是通用的,首先须要创立用户池利用。

填写利用名称,能够获取到 App ID 和 App Secret 配置。

配置回调地址,留神如果是应用 Next.js 框架,倡议用 /api/xxx 的前缀(所有接口服务必须在该目录下),如果是 Remix 框架则随便。

这步的配置不焦急,能够依据后续我的项目来进行更改。

受权配置,默认即可。目前 SDK 提供的形式也是通过 code。(后续可能会增加更多灵便的抉择,如果你对此有理解,能够集成本人的鉴权回调。)

Next.js

装置依赖

npm install --save @authing/nextjs iron-session swr# oryarn add @authing/nextjs iron-session swr

配置环境变量

config/index.ts,或者其余中央。倡议不要疏忽该步骤,将用到的变量参数对立治理。

export const clientId =  process.env.AUTHING_CLIENT_ID || '61e4da899687d7055442f6b7';export const clientSecret = process.env.AUTHING_CLIENT_SECRET || '';export const appDomain =  process.env.AUTHING_CLIENT_DOMAIN || 'https://remix.authing.cn';export const redirectUri =  process.env.AUTHING_REDIRECT_URI || 'http://localhost:3000/authing/callback';export const logoutRedirectUri =  process.env.AUTHING_LOGOUT_REDIRECT_URI || 'http://localhost:3000/';

创立 SessionStorage

创立 lib/session.ts。示例中应用的是 iron-session 进行创立。

创立登录、登记和回调 API

留神:登录 URL 为 /api/login, 登记为 /api/logout

创立 pages/api/login.ts

import { createLoginApi } from '@authing/nextjs';import { appDomain, clientId, redirectUri } from '../../config';export default createLoginApi({  appDomain,  clientId,  redirectUri,  scope: 'openid roles username phone profile'});

创立 pages/api/logout.ts

import { withIronSessionApiRoute } from 'iron-session/next';import { createLogoutApi } from '@authing/nextjs';import { appDomain, logoutRedirectUri } from '../../config';import { sessionOptions } from '../../lib/session';export default withIronSessionApiRoute(  createLogoutApi({    appDomain,    redirectUri: logoutRedirectUri  }),  sessionOptions);

创立 pages/api/callback.ts

import { createCallbackApi } from '@authing/nextjs';import { appDomain, clientId, clientSecret } from '../../config';import { withIronSessionApiRoute } from 'iron-session/next';import { sessionOptions } from '../../lib/session';export default withIronSessionApiRoute(  createCallbackApi({    appDomain,    clientId,    clientSecret,    // 登录失败返回登录页    failureRedirect: '/error',    successRedirect: '/ssr'  }),  sessionOptions);

在 SSR 中应用

参考 pages/ssr.tsx

import { withIronSessionSsr } from 'iron-session/next';import { sessionOptions } from '../lib/session';export const getServerSideProps = withIronSessionSsr(async function ({  req,  res}) {  const user = req.session.user;  if (user === undefined) {    res.setHeader('location', '/api/login');    res.statusCode = 302;    res.end();    return {      props: {        user: { isLoggedIn: false }      }    };  }  return {    props: { user: req.session.user }  };},sessionOptions);

在 SSG 中应用

创立接口: pages/api/me.ts

import { withIronSessionApiRoute } from 'iron-session/next';import { sessionOptions } from '../../lib/session';import { NextApiRequest, NextApiResponse } from 'next';export type User = {  isLoggedIn: boolean;  username: string;};export default withIronSessionApiRoute(userRoute, sessionOptions);async function userRoute(req: NextApiRequest, res: NextApiResponse<User>) {  if (req.session.user) {    // in a real world application you might read the user id from the session and then do a database request    // to get more information on the user if needed    res.json({      ...req.session.user,      isLoggedIn: true    });  } else {    res.json({      isLoggedIn: false,      username: ''    });  }}

创立钩子 hooks/use-user.ts

import { useEffect } from 'react';import Router from 'next/router';import useSWR from 'swr';import { User } from '../pages/api/me';export default function useUser({  redirectTo = '',  redirectIfFound = false} = {}) {  const { data: user, error } = useSWR<User>('/api/me');  useEffect(() => {    // if no redirect needed, just return (example: already on /dashboard)    // if user data not yet there (fetch in progress, logged in or not) then don't do anything yet    if (!redirectTo || !user) return;    if (      // If redirectTo is set, redirect if the user was not found.      (redirectTo && !redirectIfFound && !user?.isLoggedIn) ||      // If redirectIfFound is also set, redirect if the user was found      (redirectIfFound && user?.isLoggedIn)    ) {      Router.push(redirectTo);    }  }, [user, redirectIfFound, redirectTo]);  return { user, error };}

创立页面 pages/sg.tsx

import useUser from '../hooks/use-user';import Link from 'next/link';// Make sure to check https://nextjs.org/docs/basic-features/layouts for more info on how to use layoutsexport default function SgProfile() {  const { user } = useUser({    redirectTo: '/api/login'  });  return (    <>      <nav>        <Link href='/ssr'>SSR</Link> | <Link href='/api/logout'>Logout</Link>      </nav>      {user && (        <>          <pre>{JSON.stringify(user, null, 2)}</pre>        </>      )}    </>  );}

小结

从下面的例子中能够看出,在 Next.js 中应用,须要留神以下几点:

  • 你会装置更多的依赖

    • 你须要本人抉择第三方的 Session 存储计划,能够是 Cookie Session,也能够是 Redis 或者 JWT
    • 你须要优化你的我的项目代码,辨别好不同的页面类型。一般页面、SSR 页面、SSG 页面和 API(在 /api 目录下)
    • 如果不应用 SSR 你可能会依赖 SWR 之类的库去优化你页面上的申请

本示例我的项目代码下载:CSDN

Remix

装置依赖

npm install --save @authing/remix# oryarn add @authing/remix

配置环境变量

app/config.server.ts,或者其余中央。倡议不要疏忽该步骤,将用到的变量参数对立治理。

export const clientId =  process.env.AUTHING_CLIENT_ID || '61e4da899687d7055442f6b7';export const clientSecret = process.env.AUTHING_CLIENT_SECRET || '';export const appDomain =  process.env.AUTHING_CLIENT_DOMAIN || 'https://remix.authing.cn';export const redirectUri =  process.env.AUTHING_REDIRECT_URI || 'http://localhost:3000/authing/callback';export const logoutRedirectUri =  process.env.AUTHING_LOGOUT_REDIRECT_URI || 'http://localhost:3000/';

创立 SessionStorage

创立 app/services/session.server.ts

留神, Remix v1.1.3 (截止目前,2022 年 2 月)及之前版本请不要应用 CookieSession,会存在 UTF-8 编码解析谬误。

创立登录页、登记页和回调页

创立 app/routes/login.tsx

import { createLoginLoader } from '@authing/remix';import { appDomain, clientId, redirectUri } from '~/config.server';export const loader = createLoginLoader({  appDomain,  clientId,  redirectUri,  scope: 'openid roles username phone profile'});

创立 app/routes/logout.tsx

import { createLogoutLoader } from '@authing/remix';import { sessionStorage } from '~/services/session.server';import { appDomain, logoutRedirectUri } from '~/config.server';export const loader = createLogoutLoader({  redirectUri: logoutRedirectUri,  appDomain,  sessionStorage});

创立 app/routes/authing/callback.tsx

import { createCallbackLoader } from '@authing/remix';import { sessionStorage } from '~/services/session.server';import { appDomain, clientId, clientSecret } from '~/config.server';export const loader = createCallbackLoader({  appDomain,  clientId,  clientSecret,  // 登录失败返回登录页  failureRedirect: '/error',  successRedirect: '/user',  sessionStorage});

在路由中应用

import { isAuthenticated } from '@authing/remix';export const loader: LoaderFunction = async ({ request }) => {  const user = await isAuthenticated(request, sessionStorage);  return json(user || {});};// 在页面中应用const user = useLoaderData();

小结

比照来看,第一步就发现了 Remix 不须要过多的依赖,内置了一些罕用的后端性能。

但很可怜的是,在目前的版本(Remix v1.1.3),是存在重大 Bug 的,Cookie 不能存储 UTF-8 字符串,会导致登录信息无奈读取。

本示例我的项目代码下载:CSDN


如果你对 Remix 全栈框架感兴趣,能够关注我的博客: https://willin.wang