mirror of
https://github.com/logto-io/logto.git
synced 2025-01-06 20:40:08 -05:00
refactor(console): react sdk integration guide
This commit is contained in:
parent
06d279816f
commit
f7c574c8d0
5 changed files with 184 additions and 188 deletions
|
@ -2,9 +2,10 @@ import UriInputField from '@mdx/components/UriInputField';
|
|||
import Step from '@mdx/components/Step';
|
||||
import Tabs from '@mdx/components/Tabs';
|
||||
import TabItem from '@mdx/components/TabItem';
|
||||
import Alert from '@/components/Alert';
|
||||
|
||||
<Step
|
||||
title="Install SDK"
|
||||
title="Add Logto SDK as a dependency"
|
||||
subtitle="Please select your favorite package manager"
|
||||
index={0}
|
||||
activeIndex={props.activeStepIndex}
|
||||
|
@ -31,67 +32,34 @@ yarn add @logto/react
|
|||
pnpm add @logto/react
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="script" label="script">
|
||||
|
||||
```html
|
||||
<script src="https://logto.io/js/logto-sdk-react/0.1.0/logto-sdk-react.production.js" />
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="git" label="Git">
|
||||
|
||||
```bash
|
||||
git clone https://github.com/logto-io/js.git
|
||||
pnpm build
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
</Step>
|
||||
|
||||
<Step
|
||||
title="Initiate LogtoClient"
|
||||
title="Init LogtoClient"
|
||||
subtitle="1 step"
|
||||
index={1}
|
||||
activeIndex={props.activeStepIndex}
|
||||
onButtonClick={() => props.onNext(2)}
|
||||
>
|
||||
|
||||
Add the following code to your main html file. You may need client ID and authorization domain.
|
||||
Import and use `LogtoProvider` to provide a Logto context:
|
||||
|
||||
<pre>
|
||||
<code className="language-tsx">
|
||||
{`import { LogtoProvider, LogtoConfig } from '@logto/react';
|
||||
import React from 'react';
|
||||
|
||||
//...
|
||||
const config: LogtoConfig = {
|
||||
endpoint: '${props.endpoint}',
|
||||
clientId: '${props.appId}',
|
||||
};
|
||||
|
||||
const App = () => {
|
||||
const config: LogtoConfig = {
|
||||
clientId: '${props.appId}',
|
||||
endpoint: '${props.endpoint}',
|
||||
};
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<LogtoProvider config={config}>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/callback" element={<Callback />} />
|
||||
<Route
|
||||
path="/protected-resource"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<ProtectedResource />
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</LogtoProvider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
};`}
|
||||
const App = () => (
|
||||
<LogtoProvider config={config}>
|
||||
<YourAppContent />
|
||||
</LogtoProvider>
|
||||
);`}
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
|
@ -99,54 +67,74 @@ const App = () => {
|
|||
|
||||
<Step
|
||||
title="Sign In"
|
||||
subtitle="2 steps"
|
||||
subtitle="3 steps"
|
||||
index={2}
|
||||
activeIndex={props.activeStepIndex}
|
||||
onButtonClick={() => props.onNext(3)}
|
||||
>
|
||||
|
||||
### Step 1: Setup your login
|
||||
<Alert>
|
||||
In the following steps, we assume your app is running on <code>http://localhost:1234</code>.
|
||||
</Alert>
|
||||
|
||||
The Logto React SDK provides you tools and hooks to quickly implement your own authorization flow. First, let’s enter your redirect URI
|
||||
### Configure Redirect URI
|
||||
|
||||
First, let’s enter your redirect URI. E.g. `http://localhost:1234/callback`.
|
||||
|
||||
<UriInputField appId={props.appId} isSingle={!props.isCompact} name="redirectUris" title="Redirect URI" />
|
||||
|
||||
Add the following code to your web app
|
||||
### Implement a sign-in button
|
||||
|
||||
We provide two hooks `useHandleSignInCallback()` and `useLogto()` which can help you easily manage the authentication flow.
|
||||
|
||||
Go back to your IDE/editor, use the following code to implement the sign-in button:
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { useLogto } from '@logto/react';
|
||||
|
||||
const SignInButton = () => {
|
||||
const { signIn } = useLogto();
|
||||
const redirectUrl = window.location.origin + '/callback';
|
||||
const SignIn = () => {
|
||||
const { signIn, isAuthenticated } = useLogto();
|
||||
|
||||
return <button onClick={() => signIn(redirectUrl)}>Sign In</button>;
|
||||
};
|
||||
|
||||
export default SignInButton;
|
||||
```
|
||||
|
||||
### Step 2: Retrieve Auth Status
|
||||
|
||||
```tsx
|
||||
import React from "react";
|
||||
import { useLogto } from '@logto/react';
|
||||
|
||||
const App = () => {
|
||||
const { isAuthenticated, signIn } = useLogto();
|
||||
|
||||
if !(isAuthenticated) {
|
||||
return <SignInButton />
|
||||
if (isAuthenticated) {
|
||||
return <div>Signed in</div>;
|
||||
}
|
||||
|
||||
return <>
|
||||
<AppContent />
|
||||
<SignOutButton />
|
||||
</>
|
||||
return (
|
||||
<button onClick={() => signIn('http://localhost:1234/callback')}>
|
||||
Sign In
|
||||
</button>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### Handle redirect
|
||||
|
||||
We're almost there! In the last step, we use `http://localhost:1234/callback` as the Redirect URI, and now we need to handle it properly.
|
||||
|
||||
First let's create a callback component:
|
||||
|
||||
```tsx
|
||||
import { useHandleSignInCallback } from '@logto/react';
|
||||
|
||||
const Callback = () => {
|
||||
const { isLoading } = useHandleSignInCallback(() => {
|
||||
// Navigate to root path when finished
|
||||
});
|
||||
|
||||
// When it's working in progress
|
||||
if (isLoading) {
|
||||
return <div>Redirecting...</div>;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Finally insert the code below to create a `/callback` route which does NOT require authentication:
|
||||
|
||||
```tsx
|
||||
// Assuming react-router
|
||||
<Route path="/callback" element={<Callback />} />
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step
|
||||
|
@ -157,30 +145,31 @@ const App = () => {
|
|||
onButtonClick={() => props.onNext(4)}
|
||||
>
|
||||
|
||||
Execute signOut() methods will redirect users to the Logto sign out page. After a success sign out, all use session data and auth status will be cleared.
|
||||
Calling `.signOut()` will clear all the Logto data in memory and localStorage if they exist.
|
||||
|
||||
After signing out, it'll be great to redirect user back to your website. Let's add `http://localhost:1234` as the Post Sign-out URI below, and use it as the parameter when calling `.signOut()`.
|
||||
|
||||
<UriInputField appId={props.appId} isSingle={!props.isCompact} name="postLogoutRedirectUris" title="Post Sign-out Redirect URI" />
|
||||
|
||||
Add the following code to your web app
|
||||
### Implement a sign-out button
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { useLogto } from '@logto/react';
|
||||
|
||||
const SignOutButton = () => {
|
||||
const SignOut = () => {
|
||||
const { signOut } = useLogto();
|
||||
|
||||
return <button onClick={() => signOut(window.location.origin)}>Sign out</button>;
|
||||
return (
|
||||
<button onClick={() => signOut('http://localhost:1234')}>
|
||||
Sign out
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default SignOutButton;
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step
|
||||
title="Further Readings"
|
||||
subtitle="3 steps"
|
||||
title="Further readings"
|
||||
subtitle="4 articles"
|
||||
index={4}
|
||||
activeIndex={props.activeStepIndex}
|
||||
buttonText="admin_console.general.done"
|
||||
|
@ -188,8 +177,9 @@ export default SignOutButton;
|
|||
onButtonClick={props.onComplete}
|
||||
>
|
||||
|
||||
- [SDK Documentation](https://link-url-here.org)
|
||||
- [OIDC Documentation](https://link-url-here.org)
|
||||
- [Calling API to fetch accessToken](https://link-url-here.org)
|
||||
- [Customize sign-in experience](https://docs.logto.io/docs/recipes/customize-sie)
|
||||
- [Enable SMS or email passcode sign-in](https://docs.logto.io/docs/tutorials/get-started/enable-passcode-sign-in)
|
||||
- [Enable social sign-in](https://docs.logto.io/docs/tutorials/get-started/enable-social-sign-in)
|
||||
- [Protect your API](https://docs.logto.io/docs/recipes/protect-your-api)
|
||||
|
||||
</Step>
|
||||
|
|
|
@ -2,10 +2,11 @@ import UriInputField from '@mdx/components/UriInputField';
|
|||
import Step from '@mdx/components/Step';
|
||||
import Tabs from '@mdx/components/Tabs';
|
||||
import TabItem from '@mdx/components/TabItem';
|
||||
import Alert from '@/components/Alert';
|
||||
|
||||
<Step
|
||||
title="安装 SDK"
|
||||
subtitle="选择您熟悉的安装方式"
|
||||
title="将 Logto SDK 添加至依赖"
|
||||
subtitle="选择你熟悉的包管理工具"
|
||||
index={0}
|
||||
activeIndex={props.activeStepIndex}
|
||||
onButtonClick={() => props.onNext(1)}
|
||||
|
@ -31,156 +32,144 @@ yarn add @logto/react
|
|||
pnpm add @logto/react
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="script" label="script">
|
||||
|
||||
```html
|
||||
<script src="https://logto.io/js/logto-sdk-react/0.1.0/logto-sdk-react.production.js" />
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="git" label="Git">
|
||||
|
||||
```bash
|
||||
git clone https://github.com/logto-io/js.git
|
||||
pnpm build
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
</Step>
|
||||
|
||||
<Step
|
||||
title="Initiate LogtoClient"
|
||||
subtitle="1 step"
|
||||
title="初始化 LogtoClient"
|
||||
subtitle="共 1 步"
|
||||
index={1}
|
||||
activeIndex={props.activeStepIndex}
|
||||
onButtonClick={() => props.onNext(2)}
|
||||
>
|
||||
|
||||
在项目的 App.tsx 文件中,加入如下代码(需提前准备好 client ID 以及 authorization domain)
|
||||
Import 并使用 `LogtoProvider` 来提供 Logto context:
|
||||
|
||||
<pre>
|
||||
<code className="language-tsx">
|
||||
{`import { LogtoProvider, LogtoConfig } from '@logto/react';
|
||||
import React from 'react';
|
||||
|
||||
//...
|
||||
const config: LogtoConfig = {
|
||||
endpoint: '${props.endpoint}',
|
||||
clientId: '${props.appId}',
|
||||
};
|
||||
|
||||
const App = () => {
|
||||
const config: LogtoConfig = {
|
||||
clientId: '${props.appId}',
|
||||
endpoint: '${props.endpoint}',
|
||||
};
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<LogtoProvider config={config}>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/callback" element={<Callback />} />
|
||||
<Route
|
||||
path="/protected-resource"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<ProtectedResource />
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</LogtoProvider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
};`}
|
||||
const App = () => (
|
||||
<LogtoProvider config={config}>
|
||||
<YourAppContent />
|
||||
</LogtoProvider>
|
||||
);`}
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
</Step>
|
||||
|
||||
<Step
|
||||
title="Sign In"
|
||||
subtitle="2 steps"
|
||||
title="登录"
|
||||
subtitle="共 3 步"
|
||||
index={2}
|
||||
activeIndex={props.activeStepIndex}
|
||||
onButtonClick={() => props.onNext(3)}
|
||||
>
|
||||
|
||||
### Step 1: Setup your login
|
||||
<Alert>
|
||||
在如下代码示例中, 我们均先假设你的 React 应用运行在 <code>http://localhost:1234</code> 上。
|
||||
</Alert>
|
||||
|
||||
The Logto React SDK provides you tools and hooks to quickly implement your own authorization flow. First, let’s enter your redirect URI
|
||||
### 配置 Redirect URI
|
||||
|
||||
首先,我们来添加 Redirect URI,如:`http://localhost:1234/callback`
|
||||
|
||||
<UriInputField appId={props.appId} isSingle={!props.isCompact} name="redirectUris" title="Redirect URI" />
|
||||
|
||||
Add the following code to your web app
|
||||
### 实现登录按钮
|
||||
|
||||
我们提供了两个 hook 方法 `useHandleSignInCallback()` 和 `useLogto()`,它们可以帮助你轻松完成登录认证流程。
|
||||
|
||||
返回你的 IDE 或编辑器,使用如下代码来实现一个登录按钮:
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { useLogto } from '@logto/react';
|
||||
|
||||
const SignInButton = () => {
|
||||
const { signIn } = useLogto();
|
||||
const redirectUrl = window.location.origin + '/callback';
|
||||
const SignIn = () => {
|
||||
const { signIn, isAuthenticated } = useLogto();
|
||||
|
||||
return <button onClick={() => signIn(redirectUrl)}>Sign In</button>;
|
||||
};
|
||||
|
||||
export default SignInButton;
|
||||
```
|
||||
|
||||
### Step 2: Retrieve Auth Status
|
||||
|
||||
```tsx
|
||||
import React from "react";
|
||||
import { useLogto } from '@logto/react';
|
||||
|
||||
const App = () => {
|
||||
const { isAuthenticated, signIn } = useLogto();
|
||||
|
||||
if !(isAuthenticated) {
|
||||
return <SignInButton />
|
||||
if (isAuthenticated) {
|
||||
return <div>已登录</div>;
|
||||
}
|
||||
|
||||
return <>
|
||||
<AppContent />
|
||||
<SignOutButton />
|
||||
</>
|
||||
return (
|
||||
<button onClick={() => signIn('http://localhost:1234/callback')}>
|
||||
登录
|
||||
</button>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### 处理重定向
|
||||
|
||||
马上就要大功告成!在上一步,我们将 `http://localhost:1234/callback` 用作 Redirect URI,现在我们需要对其妥善处理。
|
||||
|
||||
首先,让我们来创建一个 callback 组件:
|
||||
|
||||
```tsx
|
||||
import { useHandleSignInCallback } from '@logto/react';
|
||||
|
||||
const Callback = () => {
|
||||
const { isLoading } = useHandleSignInCallback(() => {
|
||||
// 完成时跳转至根路由
|
||||
});
|
||||
|
||||
// 当登录认证尚未完成时
|
||||
if (isLoading) {
|
||||
return <div>正在重定向...</div>;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
最后我们插入如下代码来实现一个 _无需_ 登录的 `/callback` 路由:
|
||||
|
||||
```tsx
|
||||
// 假设用 react-router
|
||||
<Route path="/callback" element={<Callback />} />
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step
|
||||
title="Sign Out"
|
||||
subtitle="1 step"
|
||||
title="退出登录"
|
||||
subtitle="共 1 步"
|
||||
index={3}
|
||||
activeIndex={props.activeStepIndex}
|
||||
onButtonClick={() => props.onNext(4)}
|
||||
>
|
||||
|
||||
Execute signOut() methods will redirect users to the Logto sign out page. After a success sign out, all use session data and auth status will be cleared.
|
||||
调用 `.signOut()` 将清理内存与 localStorage 中的所有 Logto 数据(如果有)。
|
||||
|
||||
在退出登录后,让你的用户重新回到你的网站是个不错的选择。让我们将 `http://localhost:1234` 添加至下面的输入框,并将其作为调用 `.signOut()` 的参数。
|
||||
|
||||
<UriInputField appId={props.appId} isSingle={!props.isCompact} name="postLogoutRedirectUris" title="Post Sign-out Redirect URI" />
|
||||
|
||||
Add the following code to your web app
|
||||
### 实现退出登录按钮
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import { useLogto } from '@logto/react';
|
||||
|
||||
const SignOutButton = () => {
|
||||
const SignOut = () => {
|
||||
const { signOut } = useLogto();
|
||||
|
||||
return <button onClick={() => signOut(window.location.origin)}>Sign out</button>;
|
||||
return (
|
||||
<button onClick={() => signOut('http://localhost:1234')}>
|
||||
退出登录
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default SignOutButton;
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step
|
||||
title="Further Readings"
|
||||
subtitle="3 steps"
|
||||
title="延展阅读"
|
||||
subtitle="共 4 篇"
|
||||
index={4}
|
||||
activeIndex={props.activeStepIndex}
|
||||
buttonText="admin_console.general.done"
|
||||
|
@ -188,8 +177,9 @@ export default SignOutButton;
|
|||
onButtonClick={props.onComplete}
|
||||
>
|
||||
|
||||
- [SDK Documentation](https://link-url-here.org)
|
||||
- [OIDC Documentation](https://link-url-here.org)
|
||||
- [Calling API to fetch accessToken](https://link-url-here.org)
|
||||
- [Customize sign-in experience](https://docs.logto.io/zh-cn/docs/recipes/customize-sie)
|
||||
- [Enable SMS or email passcode sign-in](https://docs.logto.io/zh-cn/docs/tutorials/get-started/enable-passcode-sign-in)
|
||||
- [Enable social sign-in](https://docs.logto.io/zh-cn/docs/tutorials/get-started/enable-social-sign-in)
|
||||
- [Protect your API](https://docs.logto.io/zh-cn/docs/recipes/protect-your-api)
|
||||
|
||||
</Step>
|
||||
|
|
|
@ -83,6 +83,13 @@
|
|||
font: var(--font-body-medium);
|
||||
margin: _.unit(6) 0;
|
||||
}
|
||||
|
||||
code:not(pre > code) {
|
||||
background: var(--color-layer-2);
|
||||
font: var(--font-body-medium);
|
||||
padding: _.unit(1) _.unit(1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.card + .card {
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
display: flex;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
|
||||
.saveButton {
|
||||
position: absolute;
|
||||
left: calc(556px + _.unit(3));
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.field {
|
||||
width: 556px;
|
||||
}
|
||||
|
||||
.saveButton {
|
||||
position: absolute;
|
||||
left: calc(556px + _.unit(3));
|
||||
top: 0;
|
||||
}
|
||||
|
|
|
@ -62,8 +62,17 @@ const Guide = ({ app, isCompact, onClose }: Props) => {
|
|||
code: ({ className, children }) => {
|
||||
const [, language] = /language-(\w+)/.exec(className ?? '') ?? [];
|
||||
|
||||
return <CodeEditor isReadonly language={language} value={String(children)} />;
|
||||
return language ? (
|
||||
<CodeEditor isReadonly language={language} value={String(children)} />
|
||||
) : (
|
||||
<code>{String(children)}</code>
|
||||
);
|
||||
},
|
||||
a: ({ children, ...props }) => (
|
||||
<a {...props} target="_blank" rel="noopener noreferrer">
|
||||
{children}
|
||||
</a>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Suspense fallback={<StepsSkeleton />}>
|
||||
|
|
Loading…
Reference in a new issue