Nefariously Pushing Master

    @authok/authok-spa-js
    TypeScript icon, indicating that this package has built-in type declarations

    1.19.7 • Public • Published

    @authok/authok-spa-js

    针对单页面应用(SPA)的 Authok SDK, 采用 基于 PKCE 的认证码授权流程.

    CircleCI Release Codecov Downloads License

    目录

    文档

    安装

    从 CDN 安装:

    <script src="https://cdn.authok.cn/js/authok-spa-js/1.19/authok-spa-js.production.js"></script>

    使用 npm:

    npm install @authok/authok-spa-js

    使用 yarn:

    yarn add @authok/authok-spa-js

    开始

    Authok 配置

    Authok Dashboard 中创建一个 单页应用 .

    如果您使用的现有应用, 确认您是否在单页应用中做了如下配置:

    • 点击应用页面的 "设置" 标签栏.
    • 确保 "应用属性" 下面的 "Token Endpoint Authentication Method" 设置为 "None"
    • 滚动到页面下方并点击 "显示高级设置" 链接.
    • 在 "高级设置" 中点击 "OAuth" 标签.
    • 确保 "JsonWebToken Signature Algorithm" 设置为 RS256 并且 "OIDC Conformant" 是开启的.

    接下来,在应用 >> “设置" >> "应用 URIs" 部分配置如下 URL:

    • Allowed Callback URLs: http://localhost:3000
    • Allowed Logout URLs: http://localhost:3000
    • Allowed Web Origins: http://localhost:3000

    这些 URLs 对应的是应用运行的来源(origin). Allowed Callback URLs 还包含应用处理回调的具体路径 (见下文).

    注意 "基本信息" 中的 Client IDDomain. 下一步需要用到这些值.

    创建 client

    在渲染或初始化应用程序之前创建 AuthokClient 实例. 您应该仅创建唯一一个 client 实例.

    import createAuthokClient from '@authok/authok-spa-js';
    
    //with async/await
    const authok = await createAuthokClient({
      domain: '<AUTHOK_DOMAIN>',
      client_id: '<AUTHOK_CLIENT_ID>',
      redirect_uri: '<MY_CALLBACK_URL>'
    });
    
    //with promises
    createAuthokClient({
      domain: '<AUTHOK_DOMAIN>',
      client_id: '<AUTHOK_CLIENT_ID>',
      redirect_uri: '<MY_CALLBACK_URL>'
    }).then(authok => {
      //...
    });
    
    //或者,您可以自行实例化 client
    import { AuthokClient } from '@authok/authok-spa-js';
    
    const authok = new AuthokClient({
      domain: '<AUTHOK_DOMAIN>',
      client_id: '<AUTHOK_CLIENT_ID>',
      redirect_uri: '<MY_CALLBACK_URL>'
    });
    
    //如果自行实例化,您需要自行检查会话
    try {
      await getTokenSilently();
    } catch (error) {
      if (error.error !== 'login_required') {
        throw error;
      }
    }

    1 - 登录

    <button id="login">登录</button>
    //with async/await
    
    //重定向到统一登录页面
    document.getElementById('login').addEventListener('click', async () => {
      await authok.loginWithRedirect();
    });
    
    //在回调路由中 (<MY_CALLBACK_URL>)
    window.addEventListener('load', async () => {
      const redirectResult = await authok.handleRedirectCallback();
      //登录成功. 您可以获取用户档案:
      const user = await authok.getUser();
      console.log(user);
    });
    
    //with promises
    
    //重定向到统一登录页面
    document.getElementById('login').addEventListener('click', () => {
      authok.loginWithRedirect().catch(() => {
        //重定向发生错误
      });
    });
    
    //在回调路由中 (<MY_CALLBACK_URL>)
    window.addEventListener('load', () => {
      authok.handleRedirectCallback().then(redirectResult => {
        //登录成功. 您可以获取用户档案:
        authok.getUser().then(user => {
          console.log(user);
        });
      });
    });

    2 - 调用 API

    <button id="call-api">调用 API</button>
    //with async/await
    document.getElementById('call-api').addEventListener('click', async () => {
      const accessToken = await authok.getTokenSilently();
      const result = await fetch('https://myapi.com', {
        method: 'GET',
        headers: {
          Authorization: `Bearer ${accessToken}`
        }
      });
      const data = await result.json();
      console.log(data);
    });
    
    //with promises
    document.getElementById('call-api').addEventListener('click', () => {
      authok
        .getTokenSilently()
        .then(accessToken =>
          fetch('https://myapi.com', {
            method: 'GET',
            headers: {
              Authorization: `Bearer ${accessToken}`
            }
          })
        )
        .then(result => result.json())
        .then(data => {
          console.log(data);
        });
    });

    3 - 退登(Logout)

    <button id="logout">退登</button>
    import createAuthokClient from '@authok/authok-spa-js';
    
    document.getElementById('logout').addEventListener('click', () => {
      authok.logout();
    });

    您可以在注销后将用户重定向回您的应用. 这个 URL 必须在 Authok Dashboard >> 应用 >> Allowed Logout URLs 中进行配置:

    authok.logout({
      return_to: 'https://your.custom.url.example.com/'
    });

    数据缓存选项

    可以配置 SDK 在内存或本地存储中缓存 ID 令牌和访问令牌. 默认是在内存中. 可以在创建 Authok client 时通过 cacheLocation 选项指定.

    使用内存模式无需进行选项设置. 使用 本地存储(local storage) 模式, 需设置 cacheLocation:

    await createAuthokClient({
      domain: '<AUTHOK_DOMAIN>',
      client_id: '<AUTHOK_CLIENT_ID>',
      redirect_uri: '<MY_CALLBACK_URL>',
      cacheLocation: 'localstorage' // valid values are: 'memory' or 'localstorage'
    });

    重要: 此功能允许将 ID 和访问令牌 等数据缓存存储在本地存储中. 使用此选项会给应用程序带来安全风险, 所以 不要轻易使用. 应特别注意抵御 XSS 攻击, 避免令牌从本地存储被盗的风险.

    创建自定义缓存

    可以配置 SDK 使用应用自定义缓存. 比如您有更安全的令牌存储可被使用, 例如混合移动应用程序中.

    通过设置 SDK 配置的 cache 属性来进行自定义.

    cache 对象需要实现如下函数. 所有函数都可以返回 Promise 或静态值.

    签名 返回值 描述
    get(key) Promise 或 object 返回找到的对象, 没有找到返回 undefined
    set(key: string, object: any) Promise 或 void 设置条目到缓存
    remove(key) Promise 或 void 从缓存删除条目, 条目未找到不作任何处理
    allKeys() Promise<string[]> 或 string [] (可选) 如果您的缓存可以返回所有缓存条目的 key 列表. 否则,SDK 会在内部自行记录 key 清单. 注意: SDK 使用的 key 带有前缀 @@authokspajs@@, 如果您只想返回此 SDK 使用的 key, 可以通过此前缀进行过滤

    下面是一个自定义缓存的示例, 它使用 sessionStorage:

    const sessionStorageCache = {
      get: function (key) {
        return JSON.parse(sessionStorage.getItem(key));
      },
    
      set: function (key, value) {
        sessionStorage.setItem(key, JSON.stringify(value));
      },
    
      remove: function (key) {
        sessionStorage.removeItem(key);
      },
    
      // Optional
      allKeys: function () {
        return Object.keys(sessionStorage);
      }
    };
    
    await createAuthokClient({
      domain: '<AUTHOK_DOMAIN>',
      client_id: '<AUTHOK_CLIENT_ID>',
      redirect_uri: '<MY_CALLBACK_URL>',
      cache: sessionStorageCache
    });

    注意: 如果 cachecacheLocation 都设置的情况下 cache 优先级更高. 同时设置的情况下控制台会出现警告.

    我们同样暴露了 InMemoryCacheLocalStorageCache 的实现, 这样便于您参考实现.

    刷新令牌(Refresh Token)

    刷新令牌被用于请求新的访问令牌. 了解刷新令牌如何用于浏览器应用 来帮助您决定是否需要使用它们.

    要使用刷新令牌, 需设置 useRefreshTokens 选项为 true:

    await createAuthokClient({
      domain: '<AUTHOK_DOMAIN>',
      client_id: '<AUTHOK_CLIENT_ID>',
      redirect_uri: '<MY_CALLBACK_URL>',
      useRefreshTokens: true
    });

    此设置会让 SDK 自动发送 offline_access scope 到授权服务器. 刷新令牌 会被用于交换新的 访问令牌, 直接调用 /oauth/token 端点而非使用隐藏 iframe. 这意味着多数情况下 SDK 在使用 刷新令牌 时 不需要依赖第三方 cookies.

    注意 此配置选项需要 为你的 Authok 租户开启 轮换刷新令牌.

    刷新令牌回退

    在刷新令牌不可用的情况下, SDK 会回退到使用传统技术方案, 即使用带有 prompt=none 的隐藏 iframe 来尝试获取新的访问令牌和刷新令牌. 例如,如果您正在使用内存缓存并且刷新了页面,就会出现这种情况。在这种情况下,以前存储的任何刷新令牌都将丢失.

    如果回退机制失败,将抛出一个 login_required 错误,可以对其进行处理,以便让用户重新进行身份验证.

    注意: 此回退机制仍然需要访问 Authok 的会话 cookie,因此如果第三方 cookie 被阻止,则回退将不起作用,用户必须重新验证才能获得新的刷新令牌.

    组织

    组织 主要便于开发和维护 SaaS 和 B2B 应用.

    登录组织

    通过指定 client 的 organization 选项来登录组织:

    createAuthokClient({
      domain: '<AUTHOK_DOMAIN>',
      client_id: '<AUTHOK_CLIENT_ID>',
      redirect_uri: '<MY_CALLBACK_URL>',
      organization: '<MY_ORG_ID>'
    });

    也可以在登录时指定组织:

    // 使用重定向
    client.loginWithRedirect({
      organization: '<MY_ORG_ID>'
    });
    
    // 使用弹出窗
    client.loginWithPopup({
      organization: '<MY_ORG_ID>'
    });

    接受用户邀请

    通过 SDK 接受用户邀请, 方法是在应用程序中创建可处理用户邀请 URL 的路由, 并通过从此 URL 传递“organization”和“invitation”参数来登录用户。您可以根据需要使用 loginWithRedirectloginWithPopup.

    const url = new URL(invitationUrl);
    const params = new URLSearchParams(url.search);
    const organization = params.get('organization');
    const invitation = params.get('invitation');
    
    if (organization && invitation) {
      client.loginWithRedirect({
        organization,
        invitation
      });
    }

    高级选项

    可以在配置 AuthokClient 时通过 advancedOptions 属性来配置 高级选项. 参考 API 文档 来了解高级选项的完整设置.

    createAuthokClient({
      domain: '<AUTHOK_DOMAIN>',
      client_id: '<AUTHOK_CLIENT_ID>',
      advancedOptions: {
        defaultScope: 'email' // 修改每个 authz 请求的 scopes. **注意**: `openid` 始终都会被指定
      }
    });

    贡献

    感谢所有对本仓库的返回和贡献! 在开始之前,先参考:

    支持 + 反馈

    如需支持或提供反馈, 请 在我们的问题追踪器上提出问题.

    常见问题

    有关使用 SDK 时可能遇到的常见问题,请查看the FAQ.

    安全风险报告

    请不要在公共 GitHub 问题跟踪器上报告安全漏洞. Responsible Disclosure Program  详细说明了披露安全问题的流程.

    Authok 是什么?

    Authok 可以帮助您:

    • 使用多个身份提供者进行身份认证, 包括 社会化 (例如, 微信, 企业微信, 支付宝, 抖音, 微博, Google, Facebook, Microsoft, LinkedIn, GitHub, Twitter), 或者 企业 (例如, Windows Azure AD, Google Apps, Active Directory, ADFS, SAML)
    • 通过 用户名/密码 数据库, 免密模式, 多因素认证 等多种模式进行登录
    • 连接多个用户账号
    • 生成签名的 JSON Web 令牌以授权 API 调用并安全地传递用户身份
    • 登录方式、时间和地点等统计和分析
    • 使用可定制的 JavaScript 规则从其他数据源丰富用户档案

    为什么使用 Authok?

    许可

    本项目基于 MIT 许可. 参考 LICENSE 以了解更多信息.

    Install

    npm i @authok/authok-spa-js

    DownloadsWeekly Downloads

    4

    Version

    1.19.7

    License

    MIT

    Unpacked Size

    2.6 MB

    Total Files

    62

    Last publish

    Collaborators

    • newtalentxp