React¶
Authany 可以帮助您为 React 应用添加用户登录功能,它提供了预置的登录页面和用户设置页面,能够加快您的开发进度。
跟随这个 15 分钟教程,使用 React 和 Authany SDK 创建一个简单的应用。
说明
查看并克隆 GitHub 上的示例项目。
在 Authany 中设置应用¶
要使用 Authany 的功能,您需要一个账号和一个项目。请在 https://manage.authany.com/ 免费注册账号,并创建一个新项目以开始使用。
之后,我们需要在项目管理台中创建一个应用。
在管理台中创建应用¶
要创建客户端应用,请在 Authany 管理台左侧菜单栏中进入应用。

在管理台中导航到应用页面
接下来,在顶部工具栏中点击 ⊕新增应用。
输入应用名称,例如 “MyAwesomeApp”,然后将应用类型选择为单页应用。点击保存按钮创建应用。
配置授权重定向 URI¶
授权重定向 URI 是应用中的一个 URL,用户使用 Authany 登录后会被重定向到该地址。您需要在这个路径中调用完成身份验证(finish authentication)功能,完成登录流程。
打开刚创建的 Authany 客户端应用的 URI 部分,添加一个新的授权重定向 URI。本教程请将 http://localhost:4000/auth-redirect 添加到授权重定向 URI 列表中。
在进行下一步之前,点击保存以保留所有客户端应用配置的更改。

配置授权重定向 URI
将 Authany 添加到 React 应用¶
在本节中,我们将创建一个简单的 React 应用,并将它与 Authany 连接,让应用的用户可以登录、查看用户设置并登出账号。
步骤 1:创建一个简单的 React 项目¶
以下是搭建 React 项目脚手架的推荐步骤。如果您是将 Authany 添加到现有项目中,可以跳过这部分,直接查看下一节的步骤 2:向项目安装 Authany SDK。
使用 Vite 创建一个新的 React 项目¶
在您喜欢的文件夹中运行以下命令,使用 Vite 创建一个新的 React 项目:
接下来,运行以下命令进入新项目目录并安装依赖:
修改端口¶
在 package.json 文件中,将 script.dev 部分里 dev 字段的值改为:
这样可以让 npm run dev 命令在开发模式下于 4000 端口运行应用。
现在,您项目的文件结构应如下所示:
my-app
├── node_modules
│ └── (...)
├── package-lock.json
├── package.json
├── index.html
└── src
├── App.tsx
└── main.tsx
现在运行 npm run dev 启动项目,在浏览器中打开 http://localhost:4000 后,您将看到默认的 “Vite + React” 页面。
步骤 2:向项目安装 Authany SDK¶
在您的 React 项目目录中运行以下命令,安装 Authany Web SDK
在 src/main.tsx 中,导入 authgear 并调用 configure 函数,在应用加载时初始化一个 Authany 实例。
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import authgear from "@authgear/web"
async function init() {
try {
// configure Authgear container instance
await authgear.configure({
endpoint: import.meta.env.VITE_AUTHGEAR_ENDPOINT,
clientID: import.meta.env.VITE_AUTHGEAR_CLIENT_ID,
sessionType: "refresh_token",
});
} finally {
createRoot(document.getElementById("root")!).render(<App />);
}
}
init().catch((e) => {
// Error handling
console.error(e)
});
Authany 容器实例接受 endpoint 和 clientID 作为参数,您可以在在 Authany 中设置应用一节所创建应用的配置页面中获取这两个值。请在项目根目录下创建一个 .env 文件,并使用以下字段添加您的 Authany 客户端应用配置:
VITE_AUTHGEAR_CLIENT_ID=<CLIENT_ID>
VITE_AUTHGEAR_ENDPOINT=<AUTHGEAR_ENDPOINT>
VITE_AUTHGEAR_REDIRECT_URL=http://localhost:4000/auth-redirect
建议在 configure() 完成后再渲染应用,这样应用渲染时 Authany 已经可以使用。
说明
现在运行 npm run dev,如果 Authany SDK 配置成功,您应该会再次看到默认页面,且控制台没有报错信息
步骤 3:实现 Context Provider¶
由于我们希望在应用的各个位置引用登录状态,让我们把这个状态放进一个 context provider 中,也就是 /src/context 文件夹下的 UserProvider.tsx。
UserProvider.tsx 文件中会有一个 isLoggedIn 布尔值和一个 setIsLoggedIn 函数。isLoggedIn 这个布尔状态可以通过 onSessionStateChange 回调自动更新,该回调可以存放在本地 SDK 容器的 delegate 中。
// src/context/UserProvider.tsx
import React, { createContext, useEffect, useState, useMemo } from "react";
import authgear from "@authgear/web";
interface UserContextValue {
isLoggedIn: boolean;
}
export const UserContext = createContext<UserContextValue>({
isLoggedIn: false,
});
interface UserContextProviderProps {
children: React.ReactNode;
}
const UserContextProvider: React.FC<UserContextProviderProps> = ({
children,
}) => {
// By default the user is not logged in
const [isLoggedIn, setIsLoggedIn] = useState<boolean>(false);
useEffect(() => {
// When the sessionState changed, logged in state will also be changed
authgear.delegate = {
onSessionStateChange: (container) => {
// sessionState is now up to date
// Value of sessionState can be "NO_SESSION" or "AUTHENTICATED"
const sessionState = container.sessionState;
if (sessionState === "AUTHENTICATED") {
setIsLoggedIn(true);
} else {
setIsLoggedIn(false);
}
},
};
}, [setIsLoggedIn]);
const contextValue = useMemo<UserContextValue>(() => {
return {
isLoggedIn,
};
}, [isLoggedIn]);
return (
<UserContext.Provider value={contextValue}>{children}</UserContext.Provider>
);
};
export default UserContextProvider;
步骤 4:实现 Auth Redirect¶
接下来,我们将添加一个 “AuthRedirect” 页面,用来处理用户通过 Authany 完成身份验证后的结果。
首先,使用以下命令安装 react-router-dom:
在 src/ 文件夹中创建 AuthRedirect.tsx 组件文件。
在 Auth Redirect 组件中调用 Authany 的 finishAuthentication() 函数,将令牌发送回 Authany 服务器以换取访问令牌和刷新令牌。不用担心这些技术细节,finishAuthentication() 会替您完成全部工作,并保存身份验证数据。
身份验证完成后,UserContextProvider 中的 isLoggedIn 状态会自动被设为 true。最后,跳转回根路径(/),也就是我们的 Home 页面。
最终的 AuthRedirect.tsx 如下所示
// src/AuthRedirect.tsx
import React, { useEffect, useRef } from "react";
import { useNavigate } from "react-router-dom";
import authgear from "@authgear/web";
const AuthRedirect: React.FC = () => {
const usedToken = useRef(false);
const navigate = useNavigate();
useEffect(() => {
async function updateToken() {
try {
await authgear.finishAuthentication();
} finally {
navigate("/");
usedToken.current = true;
}
}
if (!usedToken.current) {
updateToken().catch((e) => console.error(e));
}
}, [navigate]);
return <></>;
};
export default AuthRedirect;
说明
由于在 React 18 及更高版本中,useEffect 在开发模式下会被触发两次,我们需要实现一个清理函数来防止它被触发两次。我们将使用 useRef Hook 来防止用户令牌被发送给 Authany 端点两次。
如果没有清理函数,useEffect Hook 会被触发两次,因此 finishAuthentication() 会把令牌发送给 Authany 端点两次,其中第二次会因为令牌只能使用一次而导致 “Invalid Token” 错误。
步骤 5:向应用添加路由和 Context Provider¶
现在,我们将添加一个 “Home” 页面。在 src/ 文件夹中创建 Home.tsx 组件文件。
然后导入 Home 和 AuthRedirect 作为路由,并导入 UserContextProvider 用它包裹这些路由。
最终的 App.tsx 应如下所示:
// src/App.tsx
import React from "react";
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './Home';
import AuthRedirect from './AuthRedirect';
import UserContextProvider from './context/UserProvider';
const App: React.FC = () => {
return (
<UserContextProvider>
<Router>
<Routes>
<Route path="/auth-redirect" element={<AuthRedirect />} />
<Route path="/" element={<Home />} />
</Routes>
</Router>
</UserContextProvider>
);
}
export default App;
此时的文件结构应如下所示
步骤 6:添加登录按钮¶
首先,我们将把 Authany 依赖和要用到的 React Hook 导入 Home.tsx。然后添加登录按钮,它会通过 startLogin 的点击回调调用 startAuthentication(ConfigureOptions),从而将用户重定向到登录页面。
// src/Home.tsx
import React, { useEffect, useState, useCallback, useContext } from 'react';
import authgear, { PromptOption } from '@authgear/web';
const Home: React.FC = () => {
const startLogin = useCallback(() => {
authgear
.startAuthentication({
redirectURI: import.meta.env.VITE_AUTHGEAR_REDIRECT_URL,
prompt: PromptOption.Login,
})
.then(
() => {
// started authentication, user should be redirected to Authgear
},
err => {
// failed to start authentication
}
);
}, []);
return (
<div>
<h1>Home Page</h1>
<div>
<button onClick={startLogin}>Login</button>
</div>
</div>
);
}
export default Home;
现在运行 npm run dev,点击登录按钮后,您将被重定向到 Authany 登录页面。

步骤 7:显示用户信息¶
Authany SDK 可以帮助您轻松获取已登录用户的信息。
在上一步中,用户已经成功登录,现在让我们尝试在 Home 页面上打印用户的用户 ID(sub)。
在 Home.tsx 中,我们将添加一个简单的加载界面和一条打印 Sub ID 的问候语。我们会添加两个条件渲染元素,让它们仅在用户已登录时显示;也可以让登录按钮只在用户未登录时显示。
使用 UserContext 中的 isLoggedIn 来控制页面上的组件,通过 fetchUserInfo() 获取用户信息,并访问其 sub 属性。
// src/Home.tsx
import React, { useEffect, useState, useCallback, useContext } from "react";
import authgear, { PromptOption } from "@authgear/web";
import { UserContext } from "./context/UserProvider";
const Home: React.FC = () => {
const [greetingMessage, setGreetingMessage] = useState<string>("");
const [isLoading, setIsLoading] = useState<boolean>(false);
const { isLoggedIn } = useContext(UserContext);
useEffect(() => {
async function updateGreetingMessage() {
setIsLoading(true);
try {
if (isLoggedIn) {
const userInfo = await authgear.fetchUserInfo();
setGreetingMessage("The current User sub: " + userInfo.sub);
}
} finally {
setIsLoading(false);
}
}
updateGreetingMessage().catch((e) => {
console.error(e);
});
}, [isLoggedIn]);
const startLogin = useCallback(() => {
authgear
.startAuthentication({
redirectURI: "http://localhost:4000/auth-redirect",
prompt: PromptOption.Login,
})
.then(
() => {
// started authentication, user should be redirected to Authgear
},
(err) => {
// failed to start authentication
}
);
}, []);
return (
<div>
<h1>Home Page</h1>
{isLoading && "Loading"}
{greetingMessage ? <span>{greetingMessage}</span> : null}
{!isLoggedIn && (
<div>
<button type="button" onClick={startLogin}>
Login
</button>
</div>
)}
</div>
);
};
export default Home;
再次运行应用,用户的用户 ID(sub)应该会打印在 Home 页面上。
步骤 8:添加登出按钮¶
现在,让我们添加一个仅在用户登录时显示的登出按钮。
在 Home.tsx 中,我们将使用条件渲染元素,只在用户当前已登录时显示登出按钮。
在 Home.tsx 中找到以下这一行:
在上面这一行之后新起一行,添加以下代码:
然后,添加 logout 回调:
const logout = useCallback(() => {
authgear
.logout({
redirectURI: "http://localhost:4000/",
})
.then(
() => {
setGreetingMessage('');
},
(err) => {
console.error(err);
}
);
}, []);
再次运行应用,现在我们可以通过点击登出按钮来登出。
步骤 9:打开用户设置¶
Authany 提供了内置界面,供用户设置个人属性和修改安全设置。
使用 openURL 函数打开位于 <your_app_endpoint>/settings 的设置页面
在 Home.tsx 中,为现有元素添加一个条件渲染的链接。
{isLoggedIn && (
<a target="_blank" rel="noreferrer" onClick={userSetting} href="#">
User Setting
</a>
)}
然后添加 userSetting 回调:
import authgear, { Page } from "@authgear/web";
const userSetting = useCallback((e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();
e.stopPropagation();
authgear.open(Page.Settings);
}, []);
最终的 Home.tsx 如下所示:
// src/Home.tsx
import React, { useEffect, useState, useCallback, useContext } from "react";
import { UserContext } from "./context/UserProvider";
import authgear, { Page, PromptOption } from "@authgear/web";
const Home: React.FC = () => {
const [greetingMessage, setGreetingMessage] = useState<string>("");
const [isLoading, setIsLoading] = useState<boolean>(false);
const { isLoggedIn } = useContext(UserContext);
useEffect(() => {
async function updateGreetingMessage() {
setIsLoading(true);
try {
if (isLoggedIn) {
const userInfo = await authgear.fetchUserInfo();
setGreetingMessage("The current User sub: " + userInfo.sub);
}
} finally {
setIsLoading(false);
}
}
updateGreetingMessage().catch((e) => {
console.error(e);
});
}, [isLoggedIn]);
const startLogin = useCallback(() => {
authgear
.startAuthentication({
redirectURI: "http://localhost:4000/auth-redirect",
prompt: PromptOption.Login,
})
.then(
() => {
// started authorization, user should be redirected to Authgear
},
(err) => {
// failed to start authorization
console.error(err);
}
);
}, []);
const logout = useCallback(() => {
authgear
.logout({
redirectURI: "http://localhost:4000/",
})
.then(
() => {
setGreetingMessage("");
},
(err) => {
console.error(err);
}
);
}, []);
const userSetting = useCallback((e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();
e.stopPropagation();
authgear.open(Page.Settings);
}, []);
return (
<div>
{/* eslint-disable-next-line react/forbid-elements */}
<h1>Home Page</h1>
{isLoading && "Loading"}
{greetingMessage ? <span>{greetingMessage}</span> : null}
{!isLoggedIn && (
<div>
<button type="button" onClick={startLogin}>
Login
</button>
</div>
)}
{isLoggedIn && (
<div>
<button type="button" onClick={logout}>
Logout
</button>
<br />
<a target="_blank" rel="noreferrer" onClick={userSetting} href="#">
User Setting
</a>
</div>
)}
</div>
);
};
export default Home;

后续步骤:调用 API¶
要访问后端应用服务器上受限制的资源,HTTP 请求需要在 Authorization 请求头中携带访问令牌。Web SDK 提供了 fetch 函数来自动处理这一过程,您也可以通过 authgear.accessToken 获取令牌。
选项 1:使用 Authany SDK 提供的 fetch 函数¶
Authany SDK 提供了 fetch 函数,供您调用应用服务器。这个 fetch 函数会在应用请求中自动携带 Authorization 请求头,并自动处理访问令牌的刷新。authgear.fetch 实现了 fetch 规范。
authgear
.fetch("YOUR_SERVER_URL")
.then(response => response.json())
.then(data => console.log(data));
选项 2:将访问令牌添加到 HTTP 请求头¶
您可以通过 authgear.accessToken 获取访问令牌。每次使用访问令牌之前都调用一次 refreshAccessTokenIfNeeded,该函数只会在令牌过期时才发起网络请求进行刷新。然后将访问令牌加入应用请求的 Authorization 请求头中。
authgear
.refreshAccessTokenIfNeeded()
.then(() => {
// access token is ready to use
// accessToken can be string or undefined
// it will be empty if user is not logged in or session is invalid
const accessToken = authgear.accessToken;
// include Authorization header in your application request
const headers = {
Authorization: `Bearer ${accessToken}`
};
});