挑战用五行代码集成登录系统

随着企业事务的发展,OA 体系、财税体系、CRM 体系等各类体系只增不减,权限管理也日渐力不从心。很多企业都在寻觅这样一种服务——职工只需登录个人 OA 体系的账号密码,就能够访问飞书、销售易、客户体系等运用程序。

单点登录(Single Sign On,SSO)就能够处理这一痛点。它是指一种思想或服务,用户只需运用一次登录凭据,其他所有被授权的运用都主动处于登录态。

还记得小时候看的《红楼梦》吗?

黛玉初入贾府时,轿夫抬着她进了西边角门没走两步,转弯处就换了一帮衣帽周全的小厮来抬轿,等过了垂花门,又得由婆子们引进正房大院。

假如王熙凤为贾府购买了单点登录服务,那么黛玉进贾府就不用这么处处小心、步步留意了。只需她进了大门,其他的小门就会主动翻开,畅行无阻。

假如企业自研身份模块,时间和人力本钱的投入都很大。而运用 Authing 单点登录,用几行代码就能够集成登录体系,支撑用户一致登录。

这是因为,Authing 提供完善易用的文档,而且支撑主流编程言语的 SDK 。开发者能够经过直接调用 SDK 接口与 Authing 完结集成,为多个事务软件在 web 内完结跨主域的单点登录作用。

创立自建运用

也能够运用现有运用。

在控制台的「自建运用」页面,点击「创立自建运用」,运用类型选择「单页 Web 运用」,并填入以下信息:

  • 运用称号:你的运用称号;

  • 认证地址:选择一个二级域名,有必要为合法的域名格式,例如 my-spa-app;

挑战用五行代码集成登录系统

挑战用五行代码集成登录系统

装备单点登录

参阅 自建运用 SSO 计划

修正装备 找到刚刚装备好的运用,进入运用装备页面:

挑战用五行代码集成登录系统

  • 认证装备:装备 登录回调 URL

  • 授权装备:授权形式敞开 authorization_code、refresh_token

  • 授权装备:回来类型敞开 code

  • 点击保存进行保存装备

如下图所示:

挑战用五行代码集成登录系统

挑战用五行代码集成登录系统

至此,装备完结。

装置

Authing Browser SDK 支撑经过包管理器装置、script 标签引进的办法的办法集成到你的前端事务软件。

运用 NPM 装置

$ npm install @authing/browser

运用 Yarn 装置

$ yarn add @authing/browser

运用 script 标签直接引进

<script src="https://cdn.jsdelivr.net/npm/@authing/browser"></script>
<script>
const sdk = new Authing({
  // 很重要,请细心填写!
  // 假如运用敞开 SSO,这儿就要写单点登录的“运用面板地址”;不然填写运用的“认证地址”。
  domain: '认证域名',
  appId: '运用 ID',
  // 登录回调地址,需求在控制台『运用装备 - 登录回调 URL』中指定
  redirectUri: '登录回调地址'
});
</script>

初始化

运用 ID

如图所示:

挑战用五行代码集成登录系统

认证域名

如图所示:

挑战用五行代码集成登录系统

回调地址

根据你自己的事务填写回调地址,如图所示:

挑战用五行代码集成登录系统

为了运用 Authing Browser SDK,你需求填写运用 ID、认证域名、回调地址等参数,如下示例:

import { Authing } from '@authing/browser';
const sdk = new Authing({
  // 很重要,请细心填写!
  // 假如运用敞开 SSO,这儿就要写单点登录的“运用面板地址”;不然填写运用的“认证地址”。
  domain: '认证域名',
  appId: '运用 ID',
  // 登录回调地址,需求在控制台『运用装备 - 登录回调 URL』中指定
  redirectUri: '登录回调地址'
});

登录

Authing Browser SDK 能够向 Authing 建议认证授权恳求,目前支撑三种形式:

  1. 在当时窗口转到 Authing 保管的登录页;

  2. 弹出一个窗口,在弹出的窗口中加载 Authing 保管的登录页;

  3. 静默登录。

跳转登录

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
function App() {
  const sdk = useMemo(() => {
    return new Authing({
      // 很重要,请细心填写!
      // 假如运用敞开 SSO,这儿就要写单点登录的“运用面板地址”;不然填写运用的“认证地址”。
      domain: '单点登录的“运用面板地址”',
      // 运用 ID
      appId: '运用 ID',
      // 登录回调地址,需求在控制台『运用装备 - 登录回调 URL』中指定
      redirectUri: '登录回调 URL',
    });
  }, []);
  const [loginState, setLoginState] = useState<LoginState | null>();
  /**
   * 以跳转办法翻开 Authing 保管的登录页
   */
  const login = () => {
    sdk.loginWithRedirect();
  };
  /**
   * 获取用户的登录状况
   */
  const getLoginState = useCallback(async () => {
    const state = await sdk.getLoginState();
    setLoginState(state);
  }, [sdk]);
  useEffect(() => {
    // 判别当时 URL 是否为 Authing 登录回调 URL
    if (sdk.isRedirectCallback()) {
      /**
       * 以跳转办法翻开 Authing 保管的登录页,认证成功后需求合作 handleRedirectCallback 办法,
       * 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
       */
      sdk.handleRedirectCallback().then((res) => setLoginState(res));
    } else {
      getLoginState();
    }
  }, [getLoginState, sdk]);
  return (
    <div className="App">
      <p>
        <button onClick={login}>loginWithRedirect</button>
      </p>
      <p>
        <code>{JSON.stringify(loginState)}</code>
      </p>
    </div>
  );
}
export default App;

假如你想自定义参数,也能够对以下参数进行自定义传参,如不传参将运用默许参数。

const login = () => {
  const params: {
    // 回调地址,默许为初始化参数中的 redirectUri
    redirectUri?: string;
    // 建议登录的 URL,若设置了 redirectToOriginalUri 会在登录结束后重定向回到此页面,默许为当时 URL
    originalUri?: string;
    // 即使在用户已登录时也提示用户再次登录
    forced?: boolean;
    // 自定义的中间状况,会被传递到回调端点
    customState?: any;
  } = {
    redirectUri: '回调地址',
    originalUri: '建议登录的 URL',
    forced: false,
    customState: {},
  }
  sdk.loginWithRedirect(params);
};

弹出窗口登录

你也能够在你的事务软件页面运用下面的办法,经过弹出一个新窗口的办法让用户在新窗口登录:

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
function App() {
  const sdk = useMemo(() => {
    return new Authing({
      // 很重要,请细心填写!
      // 假如运用敞开 SSO,这儿就要写单点登录的“运用面板地址”;不然填写运用的“认证地址”。
      domain: '单点登录的“运用面板地址”',
      // 运用 ID
      appId: '运用 ID',
      // 登录回调地址,需求在控制台『运用装备 - 登录回调 URL』中指定
      redirectUri: '登录回调 URL',
    });
  }, []);
  const [loginState, setLoginState] = useState<LoginState | null>();
  /**
   * 以弹窗办法翻开 Authing 保管的登录页
   */
  const login = async () => {
    const res = await sdk.loginWithPopup();
    setLoginState(res);
  };
  /**
   * 获取用户的登录状况
   */
  const getLoginState = useCallback(async () => {
    const state = await sdk.getLoginState();
    setLoginState(state);
  }, [sdk]);
  useEffect(() => {
    getLoginState();
  }, [getLoginState]);
  return (
    <div className="App">
      <p>
        <button onClick={login}>login</button>
      </p>
      <p>
        <code>{JSON.stringify(loginState)}</code>
      </p>
    </div>
  );
}
export default App;

假如你想自定义参数,也能够对以下参数进行自定义传参,如不传参将运用默许参数。

const login = async () => {
  const params: {
    // 回调地址,默许为初始化参数中的 redirectUri
    redirectUri?: string;
    // 即使在用户已登录时也提示用户再次登录
    forced?: boolean;
  } = {
    redirectUri: '回调地址',
    forced: false,
  };
  const res = await sdk.loginWithPopup(params);
  setLoginState(res);
};

静默登录

在 自建运用 SSO 计划 一文中有提到,能够将多个自建运用添加到「单点登录 SSO」面板,假如用户已经登录过其间的一个运用,那么在同一浏览器另一个标签页访问其他运用的时候,就能够完结静默登录,直接获取到用户信息,完结单点登录作用。

import React, { useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
function App() {
  const sdk = useMemo(() => {
    return new Authing({
      // 很重要,请细心填写!
      // 假如运用敞开 SSO,这儿就要写单点登录的“运用面板地址”;不然填写运用的“认证地址”。
      domain: '单点登录的“运用面板地址”',
      // 运用 ID
      appId: '运用 ID',
      // 登录回调地址,需求在控制台『运用装备 - 登录回调 URL』中指定
      redirectUri: '登录回调 URL',
    });
  }, []);
  const [loginState, setLoginState] = useState<LoginState | null>();
  useEffect(() => {
    // 判别当时 URL 是否为 Authing 登录回调 URL
    if (sdk.isRedirectCallback()) {
      console.log('redirect');
      /**
       * 以跳转办法翻开 Authing 保管的登录页,认证成功后需求合作 handleRedirectCallback 办法,
       * 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
       */
      sdk.handleRedirectCallback().then((res) => setLoginState(res));
    } else {
      console.log('normal');
      // 获取用户的登录状况
      sdk.getLoginState().then((res) => {
        if (res) {
          setLoginState(res);
        } else {
          // 假如用户没有登录,跳转认证中心
          sdk.loginWithRedirect();
        }
      });
    }
  }, [sdk]);
  return (
    <div>
      <p>
        Access Token: <code>{loginState?.accessToken}</code>
      </p>
      <p>
        User Info: <code>{JSON.stringify(loginState?.parsedIdToken)}</code>
      </p>
      <p>
        Access Token Info:
        <code>{JSON.stringify(loginState?.parsedAccessToken)}</code>
      </p>
      <p>
        Expire At: <code>{loginState?.expireAt}</code>
      </p>
    </div>
  );
}
export default App;

高档运用

每次建议登录本质是访问一个 URL 地址,能够带着许多参数。Authing Browser SDK 默许会运用缺省参数。假如你需求精细控制登录恳求参数,能够参阅本示例。

import { Authing } from '@authing/browser';
const sdk = new Authing({
  // 很重要,请细心填写!
  // 假如运用敞开 SSO,这儿就要写单点登录的“运用面板地址”;不然填写运用的“认证地址”。
  domain: '认证域名',
  appId: '运用 ID',
  // 登录回调地址,需求在控制台『运用装备 - 登录回调 URL』中指定
  redirectUri: '登录回调地址',
  // 运用侧向 Authing 恳求的权限,以空格分隔,默许为 'openid profile'
  scope: 'openid email phone profile',
  // 回调时在何处带着身份凭据,默许为 fragment
  // fragment: 在 URL hash 中带着
  // query: 在查询参数中带着
  responseMode: 'fragment',
  // 是否运用 OIDC implicit 形式替代默许的 PKCE 形式
  // 因为 implicit 形式安全性较低,不引荐运用,只用于兼容不支撑 crypto 的浏览器
  useImplicitMode: false,
  // implicit 形式回来的凭据品种,默许为 'token id_token'
  // token: 回来 Access Token
  // id_token: 回来 ID Token
  implicitResponseType: 'token id_token',
  // 是否在每次获取登录态时恳求 Authing 查看 Access Token 有效性,可用于单点登出场景,默许为 false
  // 假如设为 true,需求在控制台中将『运用装备』-『其他装备』-『检验 token 身份验证办法』设为 none
  introspectAccessToken: false,
  // 弹出窗口的宽度
  popupWidth: 500,
  // 弹出窗口的高度
  popupHeight: 600,
});

查看登录态并获取 Token

假如你想查看用户的登录态,并获取用户的 Access TokenID Token,能够调用 getLoginState 办法,假如用户没有在 Authing 登录,该办法会抛出错误:

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
function App() {
  const sdk = useMemo(() => {
    return new Authing({
      // 很重要,请细心填写!
      // 假如运用敞开 SSO,这儿就要写单点登录的“运用面板地址”;不然填写运用的“认证地址”。
      domain: '单点登录的“运用面板地址”',
      // 运用 ID
      appId: '运用 ID',
      // 登录回调地址,需求在控制台『运用装备 - 登录回调 URL』中指定
      redirectUri: '登录回调 URL',
    });
  }, []);
  const [loginState, setLoginState] = useState<LoginState | null>();
  /**
   * 以跳转办法翻开 Authing 保管的登录页
   */
  const login = () => {
    sdk.loginWithRedirect();
  };
  /**
   * 获取用户的登录状况
   */
  const getLoginState = useCallback(async () => {
    const state = await sdk.getLoginState();
    setLoginState(state);
  }, [sdk]);
  useEffect(() => {
    // 判别当时 URL 是否为 Authing 登录回调 URL
    if (sdk.isRedirectCallback()) {
      /**
       * 以跳转办法翻开 Authing 保管的登录页,认证成功后需求合作 handleRedirectCallback 办法,
       * 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
       */
      sdk.handleRedirectCallback().then((res) => setLoginState(res));
    } else {
      getLoginState();
    }
  }, [getLoginState, sdk]);
  return (
    <div className="App">
      <p>
        <button onClick={login}>login</button>
      </p>
      <p>
        <code>{JSON.stringify(loginState)}</code>
      </p>
    </div>
  );
}
export default App;

获取用户信息

你需求运用 Access Token 获取用户的个人信息:

  1. 用户初次登录成功时能够在回调函数中拿到用户的 Access Token,然后运用 Access Token 获取用户信息;

  2. 假如用户已经登录,你能够先获取用户的 Access Token ,然后运用 Access Token 获取用户信息。

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState, UserInfo } from '@authing/browser/dist/types/global';
function App() {
  const sdk = useMemo(() => {
    return new Authing({
      // 很重要,请细心填写!
      // 假如运用敞开 SSO,这儿就要写单点登录的“运用面板地址”;不然填写运用的“认证地址”。
      domain: '单点登录的“运用面板地址”',
      // 运用 ID
      appId: '运用 ID',
      // 登录回调地址,需求在控制台『运用装备 - 登录回调 URL』中指定
      redirectUri: '登录回调 URL',
    });
  }, []);
  const [loginState, setLoginState] = useState<LoginState | null>();
  const [userInfo, setUserInfo] = useState<UserInfo | null>();
  /**
   * 以跳转办法翻开 Authing 保管的登录页
   */
  const login = () => {
    sdk.loginWithRedirect();
  };
  /**
   * 获取用户的登录状况
   */
  const getLoginState = useCallback(async () => {
    const state = await sdk.getLoginState();
    setLoginState(state);
  }, [sdk]);
  /**
   * 用 Access Token 获取用户身份信息
   */
  const getUserInfo = async () => {
    if (!loginState) {
      alert("用户未登录");
      return;
    }
    const userInfo = await sdk.getUserInfo({
      accessToken: loginState?.accessToken,
    });
    setUserInfo(userInfo);
  };
  useEffect(() => {
    // 判别当时 URL 是否为 Authing 登录回调 URL
    if (sdk.isRedirectCallback()) {
      /**
       * 以跳转办法翻开 Authing 保管的登录页,认证成功后需求合作 handleRedirectCallback 办法,
       * 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
       */
      sdk.handleRedirectCallback().then((res) => setLoginState(res));
    } else {
      getLoginState();
    }
  }, [getLoginState, sdk]);
  return (
    <div className="App">
      <p>
        <button onClick={login}>login</button>&nbsp;
        <button onClick={getUserInfo}>getUserInfo</button>&nbsp;
      </p>
      <p>
        loginState:
        <code>{JSON.stringify(loginState)}</code>
      </p>
      <p>
        userInfo:
        <code>{JSON.stringify(userInfo)}</code>
      </p>
    </div>
  );
}
export default App;

退出登录

能够调用 SDK 的 logoutWithRedirect 办法退出登录。

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
function App() {
  const sdk = useMemo(() => {
    return new Authing({
      // 很重要,请细心填写!
      // 假如运用敞开 SSO,这儿就要写单点登录的“运用面板地址”;不然填写运用的“认证地址”。
      domain: '单点登录的“运用面板地址”',
      // 运用 ID
      appId: '运用 ID',
      // 登录回调地址,需求在控制台『运用装备 - 登录回调 URL』中指定
      redirectUri: '登录回调 URL',
    });
  }, []);
  const [loginState, setLoginState] = useState<LoginState | null>();
  /**
   * 以跳转办法翻开 Authing 保管的登录页
   */
  const login = () => {
    sdk.loginWithRedirect();
  };
  /**
   * 获取用户的登录状况
   */
  const getLoginState = useCallback(async () => {
    const state = await sdk.getLoginState();
    setLoginState(state);
  }, [sdk]);
  /**
   * 登出
   */
  const logout = async () => {
    await sdk.logoutWithRedirect();
  };
  useEffect(() => {
    // 判别当时 URL 是否为 Authing 登录回调 URL
    if (sdk.isRedirectCallback()) {
      /**
       * 以跳转办法翻开 Authing 保管的登录页,认证成功后需求合作 handleRedirectCallback 办法,
       * 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
       */
      sdk.handleRedirectCallback().then((res) => setLoginState(res));
    } else {
      getLoginState();
    }
  }, [getLoginState, sdk]);
  return (
    <div className="App">
      <p>
        <button onClick={login}>login</button>&nbsp;
        <button onClick={logout}>logout</button>&nbsp;
      </p>
      <p>
        loginState:
        <code>{JSON.stringify(loginState)}</code>
      </p>
    </div>
  );
}
export default App;

代码参阅 github.com/Authing/aut…

github.com/Authing/aut…

github.com/Authing/aut…

github.com/Authing/aut…

获取协助 Join us on Gitter: forum.authing.cn