前端react集成OIDC

文章目录

    • [OpenID Connect (OIDC)](#OpenID Connect (OIDC))
      • [3种 授权模式](#3种 授权模式)
    • [【服务端】express 集成OIDC](#【服务端】express 集成OIDC)
    • [【前端】react 集成OIDC](#【前端】react 集成OIDC)
      • [oidc-client-js库 原生集成](#oidc-client-js库 原生集成)
      • [react-oidc-context 库](#react-oidc-context 库)

OAuth 2.0 协议主要用于资源授权。

OpenID Connect (OIDC)

https://openid.net/specs/openid-connect-core-1_0.html

开放身份连接,是基于 OAuth 2.0协议的一个扩展。通过扩展身份层,来实现去中心化的身份验证服务。

它允许客户端验证用户身份,并获取一些基本用户信息。

使用 OIDC,应用程序可以简化身份验证和授权 流程

实现单点登录或先鉴权用户再返回资源

  • 主要包括以下角色:

    OpenID Provider(OP): 指授权服务器,负责签发 Id Token。Authing 是 OpenID Provider。

    End User(EU):资源所有者,即用户;

    ID Token:包含 EU 身份认证信息的 JWT 格式数据,是用户的身份凭证;

  • 主要特点包括:

    身份验证: OIDC 允许客户端应用程序验证用户的身份,确保只有授权的用户才能访问应用程序。

    用户信息: OIDC 提供了一种标准化的方式来获取有关已验证用户的基本信息,如用户名、电子邮件地址等。

    单点登录 (SSO): OIDC 支持单点登录,使用户只需登录一次就可以访问多个应用程序。

    安全性: OIDC 建立在 OAuth 2.0 的安全基础之上,提供了更强的安全性和隐私保护。

3种 授权模式

  1. 授权码流程
    1 前端登录,
    2 后端返回授权码(密钥) ,【前端需要安全存储密钥】
    3 授权码换token ,ID Token、Access Token,【可以反复刷新token】
    4 前端保存并携带Token
  2. 隐式流程
    1 前端登录,
    2 后端返回token ,ID Token、Access Token,
    3 前端保存并携带Token

    适用于 浏览器前端 无法安全存储密钥
  3. 混合流程

【服务端】express 集成OIDC

express-openid-connect 库

  • 应用配置
js 复制代码
const { auth } = require('express-openid-connect');

  const app = express();
  
  app.use(
    auth({
      issuerBaseURL: 'OIDC url',
      baseURL: '授权登录成功后回调 url',
      clientID: 'AUTH_CLIENT_ID',
      secret: 'AUTH_CLIENT_SECRET',
      idpLogout: true,
      session: {
        store: redisStore,
        name: '',
        cookie: {
          domain: process.env.COOKIE_DOMAIN,
        },
      },
    })
  );
  • requiresAuth() 对指定接口进行 身份验证
js 复制代码
var router = require('express').Router();
const { requiresAuth } = require('express-openid-connect');

app.get('/profile', requiresAuth(), (req, res) => {
  res.send(`hello ${req.oidc.user.name}`);
});

【前端】react 集成OIDC

oidc-client-js库 原生集成

  • 安装 oidc-client-js / oidc-client-ts
sh 复制代码
npm install oidc-client-js
  • 初始化 OIDC 客户端实例
js 复制代码
import { UserManager, WebStorageStateStore } from 'oidc-client-js';

// 配置 userManager
const userManager = new UserManager({
  authority: 'OIDC 提供商的 URL',
  client_id: ' OIDC 提供商处注册的唯一 client_id',
  redirect_uri: 'OIDC 认证后回调url',
  // 认证信息存储到 localStorage
  userStore: new WebStorageStateStore({ store: window.localStorage })
});

function Root() {
  const [pageLoaded, setLoaded] = useState(false);
  
  // 在应用程序启动时初始化 OIDC 客户端
  useEffect(() => {
    userManager.getUser().then((user) => {
      if (user && !user.expired) {
        // 如果已经登录,将 user 对象存储在组件状态中
        setUser(user);
      } else {
      
        // OIDC 登录
        userManager.signinRedirect();
      }
      setLoaded(true);
    });
  }, []);
  • 使用 OIDC 认证的 token
js 复制代码
import { userManager } from './oidc-config';

async function fetchData() {
   const user = await userManager.getUser();
   if (user && !user.expired) {
     // 如果已登录,在请求头中附带 access_token
     const response = await axios.get('/api/data', {
       headers: {
         'Authorization': `Bearer ${user.access_token}`
       }
    }
  }
}

react-oidc-context 库

react-oidc-context封装了oidc-client-ts,使用更简单

  • AuthProvider 集成 OIDC
ts 复制代码
import { AuthProvider } from 'react-oidc-context';
import { WebStorageStateStore } from 'oidc-client-ts';

const oidcConfig = {
  authority: 'OIDC 提供商的 URL',
  client_id: ' OIDC 提供商处注册的唯一 client_id',
  redirect_uri: 'OIDC 认证后回调url',
  client_secret: 'client 密钥',
  automaticSilentRenew: true,
  loadUserInfo: true,
  // 认证信息存储到 localStorage
  userStore: new WebStorageStateStore({
    store: localStorage,
  }),
  onSigninCallback: (): void => {
    window.history.replaceState({}, document.title, window.location.pathname);
  },
};

function Root() {
  const [pageLoaded, setLoaded] = useState(false);
  return (
    <React.StrictMode>
      {!pageLoaded ? <PageLoadingSpinner /> : null}
      
      <!-- 在外层使用 AuthProvider 集成OIDC -->
      <AuthProvider {...oidcConfig}>
          <RouterProvider router={routes(setLoaded)} />
      </AuthProvider>
      
    </React.StrictMode>
  );
}

ReactDOM.createRoot(document.getElementById('root')!).render(<Root />);
  • 登录逻辑
ts 复制代码
  const auth = useAuth();
  
  useEffect(() => {
    if (
      !hasAuthParams() &&
      !auth.isAuthenticated &&
      !auth.activeNavigator &&
      !auth.isLoading
    ) {
    
      // OIDC 登录
      auth.signinRedirect();
    }
  }, [auth]);
  
  // 登录成功后跳转 page
  if (auth.isAuthenticated) {
    return <>{props.children}</>;
  }
  
  // 登录报错处理
  if (auth.error) {
    console.log(auth.error);
  }

对应的http请求

- 跳转到登录页
{{authority}}/.well-known/openid-configuration
- 获取token
{{authority}}/protocol/openid-connect/token
- 获取user info
{{authority}}/protocol/openid-connect/userinfo
  • 组件Component 内获取登录信息
    组件内可以使用 const auth = useAuth(); 获取auth对象,然后得到user

    const auth = useAuth();
    const token = auth.user?.access_token;

非组件获取user信息

非组件不能使用hook,只能从userStore配置中获取 user信息

ts 复制代码
import { User } from 'oidc-client-ts';

function getUser() {
  // 之前把信息存储在了localStorage,就从localStorage获取
  const oidcStorage = localStorage.getItem(
    `oidc.user:${AUTH_URL}:${AUTH_CLIENT_ID}`
  );
  if (!oidcStorage) {
    return null;
  }
  return User.fromStorageString(oidcStorage);
}
相关推荐
王哈哈^_^1 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie2 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic2 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿2 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具3 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
qq_390161774 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test4 小时前
js下载excel示例demo
前端·javascript·excel
Yaml44 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事4 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶4 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json