準備工作
本節(jié)介紹如何將OneAuth 與您的SPA應用集成,使用OneAuth作為SPA應用的用戶存儲庫并實現用戶登錄。
如果您正在構建一個由服務器端渲染的Web應用,參考Web應用集成用戶登錄
前提條件:
已經具備了OneAuth的組織賬戶。如果沒有?免費創(chuàng)建
具備基礎的JavaScript開發(fā)經驗
有SPA應用或正在構建的工程需要接入認證流程
如果你沒有相關的應用,只是期望學習如何使用,建議參考如下的資料 :
React quickstart
教您構建Vue.js應用程序的基礎知識,React Quickstart
或者,如果您想快速開始,只需下載一個應用示例,請下載我們的React示例。
在OneAuth控制臺創(chuàng)建SPA應用
在您使用OneAuth可以登錄用戶之前,您需要在管理后臺創(chuàng)建一個單頁應用用于的OneAuth的 應用集成。
使用您的管理員帳戶登錄您的OneAuth組織。
在管理后臺,選擇 應用 > 應用
點擊 創(chuàng)建應用
選擇OIDC-Openid Connect認證方式
選擇SPA 單頁面應用 應用類型,點擊下一步
填寫應用名稱,應用描述(可選)
用戶授權方式選擇Authorization Code,這將為您的SPA啟用帶有 PKCE 的授權碼流,并能夠在訪問令牌過期時刷新訪問令牌,而不會提示用戶重新進行身份驗證。
輸入登錄重定向的地址 ,例如,添加本地開發(fā)環(huán)境的地址:
http://localhost:3000/callback,或者生產環(huán)境的地址:https://app.example.com/callback。點擊保存
添加CORS安全域名,選擇API>安全域,點擊添加域,填寫名稱和安全域的URI,例如本地調試環(huán)境
http://localhost:8080, 或者生產環(huán)境的URIhttps://app.example.com在新建的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
初始化時需要傳入 issuer, clientId, redirectUri, scopes, 這些值可以從 oneauth 控制臺得到,
實例化@oneauth/sdk-core 和@oneauth/sdk-react
@oneauth/sdk-react 提供了一個登錄重定向的頁面,和一個鑒權路由。
你需要把登錄重定向頁面配置到路由當中。
并將需要鑒權的頁面配置在鑒權路由之下。
- 實例化@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 中引入
<Security />
并放置到頁面中。
然后將@oneauth/sdk-core 的實例傳遞給
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應用,發(fā)行到期時間較短的訪問令牌并在需要時更新令牌被認為是一種最佳做法,因此在用戶會話存在的整個過程中都可能需要更新新令牌。
但是,將用戶重定向到OpenID提供方并返回會帶來用戶體驗的挑戰(zhàn),有可能會中斷用戶的體驗,因此通常不希望在正常導航期間將用戶重定向到登錄頁面。為了避免這種破壞性重定向,一個改進的措施是在應用程序中使用隱藏的iframe進行重定向,/authorize 端點允許使用名為 prompt 的請求參數,并將prompt參數設置為none,以避免中斷用戶體驗。如果 prompt 參數的值為 none,這將保證不會提示用戶登錄,無論他們是否有活動會話。
如果用戶具有有效會話,則應用程序將接收新令牌。如果沒有,應用程序將收到錯誤響應,并且可以再次重定向用戶,而無需使用prompt=none選項觸發(fā)身份驗證。OneAuth在提供SDK中包含相關的設計,使應用程序更容易執(zhí)行此操作。到目前為止,prompt參數是 SPA 維持用戶會話而不提示用戶多次登錄的唯一最佳實踐。
智能跟蹤防護 (ITP) 和增強型跟蹤防護 (ETP) 等瀏覽器隱私控制的引入會影響瀏覽器處理第三方 cookie 的方式。這些瀏覽器隱私控制防止使用 OneAuth 會話 cookie 以靜默方式更新用戶會話,這會迫使用戶重新進行身份驗證,對無縫的用戶體驗產生影響。
刷新令牌輪換為 SPA 提供了一種在 ITP 瀏覽器中維護用戶會話的解決方案。由于刷新令牌獨立于任何 cookie,因此您不必依賴 OneAuth會話 cookie 來更新訪問和 ID 令牌。
如果應用程序和 OneAuth 在同一個域中,并不會受到影響,您仍然可以使用 OneAuth 會話 cookie 并靜默更新令牌。
支持服務
如果您需要幫助或有問題,請在 OneAuth開發(fā)者論壇上發(fā)布問題 OneAuth 開發(fā)者論壇。