Google 致力于为黑人社区推动种族平等。查看具体举措

在 Web 应用程序中使用 OpenID Connect 进行身份验证

如果您已通过 Identity Platform 升级到 Firebase 身份验证,则可以使用您选择的符合 OpenID Connect (OIDC) 标准的提供商通过 Firebase 对您的用户进行身份验证。这使得使用 Firebase 本身不支持的身份提供程序成为可能。

在你开始之前

要使用 OIDC 提供商登录用户,您必须首先从提供商那里收集一些信息:

  • 客户端 ID :标识您的应用程序的提供商唯一的字符串。您的提供商可能会为您支持的每个平台分配不同的客户端 ID。这是您的提供商发布的 ID 令牌中的aud声明的值之一。

  • 客户端密码:提供者用来确认客户端 ID 所有权的密码字符串。对于每个客户端 ID,您都需要一个匹配的客户端密码。 (仅当您使用auth code flow时才需要此值,强烈建议您这样做。)

  • Issuer :标识您的提供者的字符串。此值必须是一个 URL,当附加/.well-known/openid-configuration时,它是提供者的 OIDC 发现文档的位置。例如,如果颁发者是https://auth.example.com ,则发现文档必须在https://auth.example.com/.well-known/openid-configuration可用。

获得上述信息后,启用 OpenID Connect 作为 Firebase 项目的登录提供程序:

  1. 将 Firebase 添加到您的 JavaScript 项目中。

  2. 如果您尚未使用 Identity Platform 升级到 Firebase 身份验证,请执行此操作。 OpenID Connect 身份验证仅在升级项目中可用。

  3. 在 Firebase 控制台的登录提供程序页面上,单击添加新提供程序,然后单击OpenID Connect

  4. 选择您将使用授权代码流还是隐式授权流

    如果您的提供者支持,您应该始终使用代码流。隐式流程不太安全,强烈建议不要使用它。

  5. 给这个提供者一个名字。请注意生成的提供程序 ID:类似于oidc.example-provider 。当您将登录代码添加到您的应用程序时,您将需要此 ID。

  6. 指定您的客户端 ID 和客户端密码,以及您的提供商的颁发者字符串。这些值必须与您的提供商分配给您的值完全匹配。

  7. 保存您的更改。

使用 Firebase SDK 处理登录流程

使用 OIDC 提供商通过 Firebase 对用户进行身份验证的最简单方法是使用 Firebase SDK 处理整个登录流程。

要使用 Firebase JavaScript SDK 处理登录流程,请按以下步骤操作:

  1. 使用您在 Firebase 控制台中获得的提供程序 ID 创建OAuthProvider的实例。

    Web version 9

    import { OAuthProvider } from "firebase/auth";
    
    const provider = new OAuthProvider('oidc.example-provider');
    

    Web version 8

    var provider = new firebase.auth.OAuthProvider('oidc.example-provider');
    
  2. 可选:指定要随 OAuth 请求一起发送的其他自定义 OAuth 参数。

    Web version 9

    provider.setCustomParameters({
      // Target specific email with login hint.
      login_hint: 'user@example.com'
    });
    

    Web version 8

    provider.setCustomParameters({
      // Target specific email with login hint.
      login_hint: 'user@example.com'
    });
    

    请与您的供应商核实其支持的参数。请注意,您不能使用setCustomParameters传递 Firebase 所需的参数。这些参数是client_idresponse_typeredirect_uristatescoperesponse_mode

  3. 可选:指定您希望从身份验证提供程序请求的基本配置文件之外的其他 OAuth 2.0 范围。

    Web version 9

    provider.addScope('mail.read');
    provider.addScope('calendars.read');
    

    Web version 8

    provider.addScope('mail.read');
    provider.addScope('calendars.read');
    

    请咨询您的提供商以了解其支持的范围。

  4. 使用 OAuth 提供程序对象向 Firebase 进行身份验证。

    您可以将用户重定向到提供商的登录页面或在弹出式浏览器窗口中打开登录页面。

    重定向流

    通过调用signInWithRedirect()重定向到提供者登录页面:

    Web version 9

    import { getAuth, signInWithRedirect } from "firebase/auth";
    
    const auth = getAuth();
    signInWithRedirect(auth, provider);
    

    Web version 8

    firebase.auth().signInWithRedirect(provider);
    

    用户完成登录并返回您的应用后,您可以通过调用getRedirectResult()获取登录结果。

    Web version 9

    import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    getRedirectResult(auth)
      .then((result) => {
        // User is signed in.
        // IdP data available in result.additionalUserInfo.profile.
    
        // Get the OAuth access token and ID Token
        const credential = OAuthProvider.credentialFromResult(result);
        const accessToken = credential.accessToken;
        const idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });
    

    Web version 8

    firebase.auth().getRedirectResult()
      .then((result) => {
        // IdP data available in result.additionalUserInfo.profile.
        // ...
    
        /** @type {firebase.auth.OAuthCredential} */
        var credential = result.credential;
    
        // OAuth access and id tokens can also be retrieved:
        var accessToken = credential.accessToken;
        var idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });
    

    弹出流

    Web version 9

    import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    signInWithPopup(auth, provider)
      .then((result) => {
        // User is signed in.
        // IdP data available using getAdditionalUserInfo(result)
    
        // Get the OAuth access token and ID Token
        const credential = OAuthProvider.credentialFromResult(result);
        const accessToken = credential.accessToken;
        const idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });
    

    Web version 8

    firebase.auth().signInWithPopup(provider)
      .then((result) => {
        // IdP data available in result.additionalUserInfo.profile.
        // ...
    
        /** @type {firebase.auth.OAuthCredential} */
        var credential = result.credential;
    
        // OAuth access and id tokens can also be retrieved:
        var accessToken = credential.accessToken;
        var idToken = credential.idToken;
      })
      .catch((error) => {
        // Handle error.
      });
    
  5. 虽然上述示例侧重于登录流程,但您可以使用相同的模式使用linkWithRedirect()linkWithPopup()将 OIDC 提供程序链接到现有用户,并使用 reauthenticateWithRedirect( reauthenticateWithRedirect()reauthenticateWithPopup() () 重新验证用户,可用于检索需要最近登录的敏感操作的新凭据。

手动处理登录流程

如果您已经在应用中实现了 OpenID Connect 登录流程,则可以直接使用 ID 令牌向 Firebase 进行身份验证:

Web version 9

import { getAuth, signInWithCredential, OAuthProvider } from "firebase/auth";

const provider = new OAuthProvider("oidc.example-provider");
const credential = provider.credential({
    idToken: idToken,
});
signInWithCredential(getAuth(), credential)
    .then((result) => {
        // User is signed in.
        // IdP data available in result.additionalUserInfo.profile.

        // Get the OAuth access token and ID Token
        const credential = OAuthProvider.credentialFromResult(result);
        const accessToken = credential.accessToken;
        const idToken = credential.idToken;
    })
    .catch((error) => {
        // Handle error.
    });

Web version 8

const provider = new OAuthProvider("oidc.example-provider");
const credential = provider.credential({
    idToken: idToken,
});
firebase.auth().signInWithCredential(credential)
    .then((result) => {
        // User is signed in.
        // IdP data available in result.additionalUserInfo.profile.

        // Get the OAuth access token and ID Token
        const credential = OAuthProvider.credentialFromResult(result);
        const accessToken = credential.accessToken;
        const idToken = credential.idToken;
    })
    .catch((error) => {
        // Handle error.
    });