使用React快速集成OneAuth现代IDaaS身份


准备工作

本节介绍如何将OneAuth 与您的SPA应用集成,使用OneAuth作为SPA应用的用户存储库并实现用户登录。

如果您正在构建一个由服务器端渲染的Web应用,参考Web应用集成用户登录

前提条件:

  • 已经具备了OneAuth的组织账户。如果没有?免费创建

  • 具备基础的JavaScript开发经验

  • 有SPA应用或正在构建的工程需要接入认证流程

如果你没有相关的应用,只是期望学习如何使用,建议参考如下的资料 :

React quickstart

教您构建Vue.js应用程序的基础知识,React Quickstart

或者,如果您想快速开始,只需下载一个应用示例,请下载我们的React示例

在OneAuth控制台创建SPA应用

在您使用OneAuth可以登录用户之前,您需要在管理后台创建一个单页应用用于的OneAuth的 应用集成。

  1. 使用您的管理员帐户登录您的OneAuth组织。

  2. 在管理后台,选择 应用 > 应用

  3. 点击 创建应用

  4. 选择OIDC-Openid Connect认证方式

  5. 选择SPA 单页面应用 应用类型,点击下一步

  6. 填写应用名称,应用描述(可选)

  7. 用户授权方式选择Authorization Code,这将为您的SPA启用带有 PKCE 的授权码流,并能够在访问令牌过期时刷新访问令牌,而不会提示用户重新进行身份验证。

  8. 输入登录重定向的地址 ,例如,添加本地开发环境的地址:http://localhost:3000/callback,或者生产环境的地址:https://app.example.com/callback

  9. 点击保存

  10. 添加CORS安全域名,选择API>安全域,点击添加域,填写名称和安全域的URI,例如本地调试环境http://localhost:8080, 或者生产环境的URIhttps://app.example.com

  11. 在新建的SPA应用的授权用户 Tab页面,选择授权给Everyone或需要限制在某个Group进行访问。

安装SDK

npm i --save @oneauth/sdk-core @oneauth/sdk-react

@oneauth/sdk-core 会提供登录登出和鉴权所需的方法,@oneauth/sdk-react 中会提供对路由的鉴权功能和准备好的登录重定向页面

@oneauth/sdk-core 可单独使用。也可搭配@oneauth/sdk-react 使用。本文使用@oneauth/sdk-core 和@oneauth/sdk-react 共同来完成集成。

配置 @oneauth/sdk-react

初始化时需要传入 issuerclientIdredirectUriscopes, 这些值可以从 oneauth 控制台得到,

实例化@oneauth/sdk-core 和@oneauth/sdk-react

@oneauth/sdk-react 提供了一个登录重定向的页面,和一个鉴权路由。

你需要把登录重定向页面配置到路由当中。

并将需要鉴权的页面配置在鉴权路由之下。

  1. 实例化@oneauth/sdk-core

import OneAuth from '@oneauth/sdk-core'
import { Security, LoginCallback, SecurityRoute } from '@oneauth/sdk-react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
function App() {
 const oneAuth = new OneAuth({
   issuer: `kang.oneauth.cn/oauth/v1`,
   clientId: `2YXXZ78611K0c8906MX6RJ8c0s84VcQB`,
   redirectUri: `http://localhost:3000/callback`,
   scopes: ['openid', 'profile', 'email'],
})
 return <>{/** 省略 **/}</>
}
?
export default App
?

 

添加一个登录按钮

import OneAuth from '@oneauth/sdk-core'
import { Security, LoginCallback, SecurityRoute } from '@oneauth/sdk-react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
function App() {
 const oneAuth = new OneAuth({
   issuer: `kang.oneauth.cn/oauth/v1`,
   clientId: `2YXXZ78611K0c8906MX6RJ8c0s84VcQB`,
   redirectUri: `http://localhost:3000/callback`,
   scopes: ['openid', 'profile', 'email'],
})
 //添加一个登录按钮
 const login = () => oneAuth.login()
 return (
   <>
     <button onClick={login}>Login</button>
   </>
)
}
?
export default App

添加路由

需要从@oneauth/sdk-react 中引入

并放置到页面中。

然后将@oneauth/sdk-core 的实例传递给

<Security oneAuth={oneAuth} />
import './App.css'
import OneAuth from '@oneauth/sdk-core'
import { Security, LoginCallback, SecurityRoute } from '@oneauth/sdk-react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
import { About } from './about'
function App() {
 const oneAuth = new OneAuth({
   issuer: `kang.oneauth.cn/oauth/v1`,
   clientId: `2YXXZ78611K0c8906MX6RJ8c0s84VcQB`,
   redirectUri: `http://localhost:3000/callback`,
   scopes: ['openid', 'profile', 'email'],
})
 const login = () => oneAuth.login()
 return (
   <BrowserRouter>
     <div className="App">
       <Security oneAuth={oneAuth}>
         <button onClick={login}>Login</button>
         <br />
         <Link to="/home">Home</Link>
         <Link to="/about">About</Link>
         <Route path="/home">
           <h1>Home</h1>
         </Route>
         <Route path="/about">
           <h1>About</h1>
         </Route>
       </Security>
     </div>
   </BrowserRouter>
)
}
?
export default App

添加登录重定向页面

配置登录重定向页面的路由时,

需与@oneauth/sdk-core 的实例化参数redirectUri一致。

import './App.css'
import OneAuth from '@oneauth/sdk-core'
import { Security, LoginCallback, SecurityRoute } from '@oneauth/sdk-react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
import { About } from './about'
function App() {
 const oneAuth = new OneAuth({
   issuer: `kang.oneauth.cn/oauth/v1`,
   clientId: `2YXXZ78611K0c8906MX6RJ8c0s84VcQB`,
   redirectUri: `http://localhost:3000/callback`,
   scopes: ['openid', 'profile', 'email'],
})
 const login = () => oneAuth.login()
 return (
   <BrowserRouter>
     <div className="App">
       <Security oneAuth={oneAuth}>
         <button onClick={login}>Login</button>
         <br />
         <Link to="/home">Home</Link>
         <Link to="/about">About</Link>
         <Route path="/home">
           <h1>Home</h1>
         </Route>
         <Route path="/about">
           <h1>About</h1>
         </Route>
         <Route path="/callback">
           <LoginCallback />
         </Route>
       </Security>
     </div>
   </BrowserRouter>
)
}
?
export default App

添加安全路由

给 about 页面添加鉴权

如此一来,每次打开 about 页面时都会检查用户是否登录了。

如果没有登录则会跳转到登录页。

登录完成后会跳转回来。

import './App.css'
import OneAuth from '@oneauth/sdk-core'
import { Security, LoginCallback, SecurityRoute } from '@oneauth/sdk-react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
import { About } from './about'
function App() {
 const oneAuth = new OneAuth({
   issuer: `kang.oneauth.cn/oauth/v1`,
   clientId: `2YXXZ78611K0c8906MX6RJ8c0s84VcQB`,
   redirectUri: `http://localhost:3000/callback`,
   scopes: ['openid', 'profile', 'email'],
})
 const login = () => oneAuth.login()
 return (
   <BrowserRouter>
     <div className="App">
       <Security oneAuth={oneAuth}>
         <button onClick={login}>Login</button>
         <br />
         <Link to="/home">Home</Link>
         <Link to="/about">About</Link>
         <Route path="/home">
           <h1>Home</h1>
         </Route>
         <SecurityRoute path="/about">
           <About />
         </SecurityRoute>
         <Route path="/callback">
           <LoginCallback />
         </Route>
       </Security>
     </div>
   </BrowserRouter>
)
}
?
export default App

SPA与刷新令牌(Refresh token)

作为公共客户端实现的单页应用(SPA)程序,无法安全地在浏览器中存储和处理刷新令牌,因此必须使用不依赖刷新令牌的方法,除非其授权服务器对刷新令牌的泄漏风险采取了安全措施(如使用刷新令牌轮换或具有使用约束条件的刷新令牌)。在许多情况下,尤其是对于公共客户机的SPA应用,发行到期时间较短的访问令牌并在需要时更新令牌被认为是一种最佳做法,因此在用户会话存在的整个过程中都可能需要更新新令牌。

但是,将用户重定向到OpenID提供方并返回会带来用户体验的挑战,有可能会中断用户的体验,因此通常不希望在正常导航期间将用户重定向到登录页面。为了避免这种破坏性重定向,一个改进的措施是在应用程序中使用隐藏的iframe进行重定向,/authorize 端点允许使用名为 prompt 的请求参数,并将prompt参数设置为none,以避免中断用户体验。如果 prompt 参数的值为 none,这将保证不会提示用户登录,无论他们是否有活动会话。

如果用户具有有效会话,则应用程序将接收新令牌。如果没有,应用程序将收到错误响应,并且可以再次重定向用户,而无需使用prompt=none选项触发身份验证。OneAuth在提供SDK中包含相关的设计,使应用程序更容易执行此操作。到目前为止,prompt参数是 SPA 维持用户会话而不提示用户多次登录的唯一最佳实践。

智能跟踪防护 (ITP) 和增强型跟踪防护 (ETP) 等浏览器隐私控制的引入会影响浏览器处理第三方 cookie 的方式。这些浏览器隐私控制防止使用 OneAuth 会话 cookie 以静默方式更新用户会话,这会迫使用户重新进行身份验证,对无缝的用户体验产生影响。

OneAuth 开发者论坛