对大多数应用程序来说,验证用户的身份是最重要的。建立你自己的认证系统一开始可能很简单,但当你考虑到安全桥梁和与第三方(如谷歌或Facebook)整合的便利性时,你可以看到建立和维护你自己的认证系统会很快变得乏味和复杂。
一个好的方法是使用一个专门处理认证的解决方案,如Okta。Okta为你提供了一个专门的安全专家团队,这样你就不必担心处理用户数据的麻烦了。
在本教程中,我们将告诉你如何在React中实现Okta认证。要跟着学习,你应该熟悉JavaScript和React Hooks。
设置一个React应用程序
第一个要求是注册Okta的开发者版本。这样我们就可以进入管理面板,在那里我们将创建登录方法和我们的应用程序类型--在我们的例子中,是一个单页应用程序(SPA)。
开始与Okta集成的应用路径。
在应用路径下,我们可以生成一个应用集成(我们的登录方式)。
选择登录方式的应用集成按钮。
点击 "创建应用集成"按钮,会生成一个包含登录方法的对话框。由于我们的应用程序是一个SPA,而且我们没有连接到后台,我们将使用OpenID Connect登录方法,它为我们提供了一个登录小部件(我们以后也会建立我们自己的自定义登录表格)。
在选择应用集成后,我们要选择单页应用并继续。
下一步是指定一个签到重定向URI(一个回调URI)。这非常重要,因为当使用OpenID Connect登录方法时,我们会被重定向到Okta托管的登录小工具(与我们的应用程序不同的端点),并且需要一个回调URL,Okta会将用户的详细信息返回给我们的应用程序。
你也可以指定其他路由,比如签出重定向URI,当我们注销应用程序时,它是应用程序应该被重定向到的页面。对于我们的用例,我们可以指定基本URL/登录路线作为我们的注销端点,这意味着用户会被重定向到登陆页面或登录页面,这取决于我们指定的端点。如果你不指定端点,用户就会被重定向到Okta的登录小工具上
Base URI是可选的。如果你打算自我托管Okta签到小工具,这很有用,但不在本教程的范围内。
与React集成
现在我们已经准备好了与Okta的应用集成,让我们把它与我们的React应用集成。
在处理这个集成时,要特别注意客户ID和Okta域,这两个都可以在应用标签中找到。
第一步是安装Okta SDK和Okta Auth JavaScript SDK。
# yarn
yarn add @okta/okta-auth-js @okta/okta-react
# npm
npm install --save @okta/okta-auth-js @okta/okta-react
让我们为我们的Okta配置数据创建环境变量(以.env 文件的形式)。
OKTA_DOMAIN=<YOUR_OKTA_DOMAIN>
CLIENT_ID=<YOUR_CLIENT_ID>
CALLBACK_PATH='/login/callback'
ISSUER='https://<YOUR_OKTA_DOMAIN>/oauth2/default'
HOST='window.location.host'
SCOPES='openid profile email'
现在我们可以配置我们的应用程序来使用Okta。
import React from "react";
import { BrowserRouter as Router, Route, useHistory } from "react-router-dom";
import { Security, SecureRoute } from "@okta/okta-react";
import { OktaAuth, toRelativeUrl } from "@okta/okta-auth-js";
import { LandingPage } from "./LandingPage";
import { Dashboard } from "./Dashboard";
import { Header } from "./Header";
const CLIENT_ID = process.env.CLIENT_ID;
const CALLBACK_PATH = process.env.CALLBACK_PATH;
const ISSUER = process.env.ISSUER;
const HOST = process.env.HOST;
const REDIRECT_URI = `http://${HOST}${CALLBACK_PATH}`;
const SCOPES = process.env.SCOPES;
if (!SCOPES || !CLIENT_ID || !CALLBACK_PATH || !ISSUER || !HOST) {
throw new Error("All environmental variables must be set");
}
const config = {
issuer: ISSUER,
clientId: CLIENT_ID,
redirectUri: REDIRECT_URI,
scopes: SCOPES.split(/\s+/),
};
const oktaAuth = new OktaAuth(config);
const App = () => {
const history = useHistory();
const restoreOriginalUri = async (_oktaAuth: any, originalUri: any) => {
history.replace(toRelativeUrl(originalUri || "/", window.location.origin));
};
return (
<Router>
<Security restoreOriginalUri={restoreOriginalUri} oktaAuth={oktaAuth}>
<Header />
<Route path="/" exact={true} component={LandingPage} />
<SecureRoute path="/dashboard" exact={true} component={Dashboard} />
</Security>
</Router>
);
};
export default App;
一个新的oktaAuth 实例是用配置对象创建的。这将被传递到安全组件中,该组件封装了我们应用程序的所有路由,并为其所有的子代(路由中的组件)提供oktaAuth 和authState 对象。
oktaAuth 对象可以用来改变或读取关于认证状态的信息。
authState 对象包含。
isAuthenticated,一个布尔值,表示用户是否被认证。如果idToken和accessToken中存在,该值为真。tokenManageraccessToken, 一个分配给当前认证用户的JWT访问令牌idToken, 一个分配给当前认证用户的JWT ID令牌error,如果认证过程失败,则返回该标志。
还请注意,我们不需要处理SecureRoute ourselves ;Okta提供了一个开箱即用的路由,它可以保护指定的路径。
让我们实现一个登录按钮来触发签到小部件。这在标题组件中很常见,所以我们将在那里处理它。
我们被提供了一个useOktaAuth 钩子,它让我们可以访问oktaAuth 和authState 对象。
import React from "react";
import { useOktaAuth } from "@okta/okta-react";
function Header() {
const { authState, oktaAuth } = useOktaAuth();
const loginWithRedirect = () =>
oktaAuth.signInWithRedirect({ originalUri: "/dashboard" });
const logOut = () => oktaAuth.signOut();
const buttonText = authState.isAuthenticated ? "Logout" : "Login";
const btnLogic = authState.isAuthenticated ? logOut : loginWithRedirect;
return (
<>
<div>Okta React</div>
<button onClick={btnLogic}>{buttonText}</button>
</>
);
}
export { Header };
我们使用authState 来确定我们是否要登录或退出我们的应用程序。
loginWithRedirect 函数处理登录触发器,在成功登录时重定向到仪表板路由,如下图所示。
登录后,用户会立即被重定向到仪表盘路由。
为了使注销功能在localhost中工作,我们需要将localhost添加到我们的信任路由列表中。这将允许在我们的应用程序中跨源。
现在,如果我们点击标题中的注销按钮,它会成功地将我们的用户注销,并将他们重定向到登陆页面。
我们成功了!我们已经在React应用程序中成功实现了Okta认证。
自定义签到表单
Okta的登录界面很好,也很容易上手,但假设我们想实现一个设计独特的自定义登录表单,同时让我们的用户留在页面上而不重定向到Okta。
我们可以通过调用useOktaAuth 钩子时提供的oktaAuth 来实现这一点。
让我们来实现一个自定义的签到表单。
import React from "react";
import { useOktaAuth } from "@okta/okta-react/bundles/types";
function SignIn() {
const { oktaAuth } = useOktaAuth();
const [sessionToken, setSessionToken] = React.useState<string | null>(null);
const onSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
const username = event.currentTarget.elements.namedItem(
"username"
) as HTMLInputElement;
const password = event.currentTarget.elements.namedItem(
"password"
) as HTMLInputElement;
const data = {
username: username.value,
password: password.value,
};
oktaAuth
.signInWithCredentials(data)
.then((res) => {
const sessionToken = res.sessionToken;
if (!sessionToken) {
throw new Error("authentication process failed");
}
setSessionToken(sessionToken);
oktaAuth.signInWithRedirect({
originalUri: "/dashboard",
// @ts-ignore
sessionToken: sessionToken,
});
})
.catch((err) => console.log("handle error here": err));
};
if (sessionToken) return <div />;
return (
<div>
<form onSubmit={onSubmit}>
<label htmlFor="username">Username</label>
<input type="text" id="username" />
<label htmlFor="password">Password</label>
<input type="password" id="password" />
<button type="submit">SignIn</button>
</form>
</div>
);
}
export { SignIn };
我们有自己的表单,我们利用oktaAuth 中的signInWithCredentials 选项来处理一个自定义的表单提交。sessionToken ,是一个一次性使用的令牌,是成功认证后收到的值。当调用useOktaAuth 钩子时,我们仍然可以通过authState 对象中提供的ID或访问令牌获得详细信息。
登录成功后,我们可以使用signInWithRedirect 函数将用户发送到原始URI(主要是受保护的仪表盘路由),同时包括sessionToken 。
让我们运行我们的应用程序,将登录按钮连接到这个登录表单的端点,同时更新我们的路由。
import React from "react";
import { useOktaAuth } from "@okta/okta-react";
import { Link } from "react-router-dom";
function Header() {
const { authState, oktaAuth } = useOktaAuth();
if (!authState) return null;
const logOutRedirect = async () => await oktaAuth.signOut();
function btnToRender() {
return authState.isAuthenticated ? (
<button onClick={logOutRedirect}>LogOut</button>
) : (
<button>
<Link to="/login">Login</Link>
</button>
);
}
return (
<>
<div>Okta React</div>
{btnToRender()}
</>
);
}
export { Header };
路线的更新如下所示。
<Security restoreOriginalUri={restoreOriginalUri} oktaAuth={oktaAuth}>
<Header />
<Route path="/" exact={true} component={LandingPage} />
<Route path="/login" component={SignIn} />
<SecureRoute path="/dashboard" exact={true} component={Dashboard} />
<Route path={CALLBACK_PATH} component={LoginCallback} />
</Security>
现在,当我们点击我们的登录按钮时,我们被重定向到登录页面。
祝贺你!你已经成功地实现了一个自定义的登录。你已经成功地在你的React应用中用Okta实现了一个自定义的登录界面。
结论
用户数据是非常微妙的信息,如果被泄露,会导致严重的隐私问题。在本教程中,我们向你展示了如何在React应用中用Okta实现一个更安全的方式来处理认证。
对于不构建后端服务的前端开发者来说--考虑到JAMStack和serverless等框架的兴起,使你能够在没有实际API服务器的情况下构建应用程序--Okta提供了一种在React应用程序中实现身份验证的好方法,而没有过多的复杂性。
The postImplementing Okta authentication in a React appappeared first onLogRocket Blog.