如何在没有 Amplify 的情况下使用 Amazon Cognito

How to use Amazon Cognito without Amplify

我刚刚开始研究 Cognito。 AWS 设置相当直接、简单。

我们有各种应用程序、网络应用程序和服务,我们希望它们能够使用 Cognito 服务。我有使用 Auth0 进行类似设置的经验,但是因为我们一直在利用许多 Amazon Web Services,所以使用 Cognito 也确实有意义。

无论我在哪里看,每个指南最终都会引用 Amplify 客户端库和 cli。我们有现有的应用程序和服务,真的不想更改工具或导入任何不必要的东西来增加膨胀和复杂性。有没有办法在没有 Amplify 库的情况下使用 Cognito 服务?是否有用于连接 Cognito 服务、身份验证和授权流程的轻量级 Cognito 专用客户端库?

2021 年 12 月 3 日更新

2021 年 re:Invent 之后,“Amplify Admin UI”更名为“Amplify Studio”。现在拥有额外的权力:

  • 自动将 Figma 中的设计转换为人类可读的 React UI 组件代码

https://aws.amazon.com/blogs/mobile/aws-amplify-studio-figma-to-fullstack-react-app-with-minimal-programming/

===============

原答案

首先,我想澄清一下,“放大”是多种事物的总称。我们有:

  1. 扩增文库 (UI/JS)
  2. Amplify CLI(创建云原生应用程序)
  3. Amplify 控制台(ci/cd 和托管全栈网络应用程序)
  4. Amplify Admin UI(UI 创建和配置全栈网络应用程序)

您可以查看主页以获得更多说明 - https://docs.amplify.aws/

Is there a lightweight Cognito-only client library for interfacing with the Cognito service, authentication-and-authorization flow?

在幕后,Amplify 使用 amazon-cognito-identity-js 库与 Amazon Cognito 交互。您可以直接通过 npm install amazon-cognito-identity-js.

安装

源代码已移至 Amplify Libraries (e.g. amplify-js) 存储库。再次是第一个类别“放大库”下的“放大”保护伞的一部分。

Is there a way to use Cognito service without Amplify libraries?

您可以采用的另一种方法是使用 Amazon Cognito 作为 OAuth 服务器。当您创建一个 Amazon Cognito Hosted UI Domain 时,它会为您提供一个符合 OAuth 2.0 的授权服务器。

您可以为 Signup/Login 端点创建自己的 API/Backend 并与 Amazon Cognito OAuth 服务器交换 tokens/credentials,而无需使用 aws-sdk 或任何第 3 方依赖库。

我写了一个演练示例,如何配置您的用户池,您需要使用 Node.js 与之通信的端点,您可以在这里找到它:https://github.com/oieduardorabelo/node-amazon-cognito-oauth

您可以对任何其他语言遵循相同的想法。

几年前我写了一篇文章解释如何做到这一点。

这篇文章谈到了 Amplify,但正如在另一个回复中提到的,这更像是一个总称,在本文中我们主要使用 Amplify 项目提供的 UI 组件。

你可以在这里找到它:https://medium.com/@mim3dot/aws-amplify-cognito-part-2-ui-components-935876fabad3

如@oieduardorabelo 所述,您只需安装 'amazon-cognito-identity-js',您还可以在其中找到做得很好的示例 on npm

这是我的测试代码,可以轻松理解这个库。您必须已经在 AWS 上构建了基础设施(userPool、userClient 并添加一个新用户来测试登录——在我的例子中,用户必须在第一次登录时更改密码,所以我在我的脚本中添加了这个用例):

import * as AmazonCognitoIdentity from 'amazon-cognito-identity-js';

var authenticationData = {
  Username: 'email',
  Password: 'password',
};
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
var poolData = {
  UserPoolId: 'us-east-1_userpoolid',
  ClientId: '26pjexamplejpkvt'
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var cognitoUser = userPool.getCurrentUser();

console.log(cognitoUser);

if (!cognitoUser) {

  var userData = {
    Username: authenticationData.Username,
    Pool: userPool
  };
  var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
  cognitoUser.authenticateUser(authenticationDetails, {
    onSuccess: function (result) {
      var accessToken = result.getAccessToken().getJwtToken();
      var idToken = result.idToken.jwtToken;
      console.log('Success', accessToken, idToken);
    },
    newPasswordRequired: function (userAttributes, requiredAttributes) {
      delete userAttributes.email_verified;
      cognitoUser.completeNewPasswordChallenge('DemoPassword1!', userAttributes, {
        onSuccess: (data) => {
          console.log(data);
        },
        onFailure: function (err) {
          alert(err);
        }
      });
    },
    onFailure: function (err) {
      alert(err);
    },

  });
}

如果有人有兴趣从头开始设置这个测试项目运行:

npm init -y
npm i -D webpack webpack-cli
npm i amazon-cognito-identity-js

在webpack.config.js中:

var path = require('path');

module.exports = {
  entry: './src/app.js',
  mode: 'development',
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: 'main.js',
  }
}

在 ./src/app.js 中创建一个新文件,其中使用正确的 AWS 信息引用添加先前的 amazonCognitoIdentity 代码并创建 ./dist/index.html whith:

...
<body>
  <script src="main.js"></script>
</body>

在package.json中添加脚本“watch”:

...
"scripts": {
    "watch": "webpack --watch",
}

终于运行啦:

npm run watch

并直接在带有开发控制台的浏览器上打开 index.html。

希望对某人有用。

作为对在 React 中不使用 Amplify 的情况下使用 Amazon Cognito 的主题的研究结果,我遇到了这样一个沙箱。从路由器 5 切换到路由器 6 可能不会有问题。这里的主要黄金是这个钩子。其余的实现可以在沙箱中找到:https://codesandbox.io/s/cognito-forked-f02htu

const Pool_Data = {
  UserPoolId: "xxx",
  ClientId: "yyy"
};

export default function useHandler() {
  const [state, setstate] = useState({
    loading: false,
    isAuthenticated: false
  });

  const { loading, isAuthenticated } = state;

  const userPool = new CognitoUserPool(Pool_Data);

  const getAuthenticatedUser = useCallback(() => {
    return userPool.getCurrentUser();
  }, []);

  console.log(getAuthenticatedUser());

  useEffect(() => {
    getAuthenticatedUser();
  }, [getAuthenticatedUser]);

  const signOut = () => {
    return userPool.getCurrentUser()?.signOut();
  };
  console.log("I am here", getAuthenticatedUser()?.getUsername());

  return {
    loading,
    isAuthenticated,
    userPool,
    getAuthenticatedUser,
    signOut
  };
}