Cognito / Flask / React:如何登录到后端?

时间:2018-12-13 21:12:35

标签: reactjs authentication flask jwt amazon-cognito

我的Web应用程序在前端使用React,在后端使用Flask

我想添加AWS Cognito进行用户管理。根据{{​​3}},这只需要在前端包装export语句即可,即更改一行

export default App;

App.js文件中(定义了主应用程序React组件)到

export default withAuthenticator(App, true);

加上所需的import语句。

这项微不足道的更改使我获得了生产中使用的任何合理的Web应用程序所需的所有以用户为中心的功能,例如

  • 用户注册
  • 电子邮件验证
  • 登录/注销
  • 忘记密码
  • 等pp。

包括

  • 可使用的用户界面
  • 电子邮件发送服务
  • 联合登录(例如Google,Facebook等)

问题:我不知道如何将其与后端集成。

方法:(我认为应该如此)

  1. 现有用户使用Cognito提供并由前端显示的UI元素登录Web应用程序
  2. 成功登录后,Cognito通过documentation使用户数据可用; currentAuthenticatedUser()(JWT)
  3. 无论何时前端将请求发送到后端,它都会将该JWT传递为请求标头
  4. 后端使用该JWT来确定用户是否已正确登录,向哪个用户发出请求以及该用户是否具有足够的权限

我已经实现了通常的Flask /login/logout请求处理程序以及一个login_required装饰器,并且还传递了JWT和解码声明,效果很好; 但是,我看不到前端应在哪里通知后端有关用户登录的信息。

我尝试使用JSON Web Token进行此操作,但这有很多缺点:

对于初学者来说,由用户登录触发的AWS lambda函数必须能够访问后端,因此它必须是公开可用的。出于安全原因,我实际上希望后端仅对前端可见/可访问。另外,在开发过程中,我在MacBook的Docker容器中同时运行前端和后端。这种方法迫使我至少在云中运行后端。

最大的问题是它不起作用:从后端的角度来看,来自前端和Cognito的请求是在单独的会话中进行的,因此,即使用户使用Cognito(通过前端),然后Cognito会通过lambda触发器通知后端有关此登录的信息,从后端到后端的任何后续请求(从后端到后端的请求)都不会与后端和Cognito之间的(经过身份验证的)会话相关联,因此未经身份验证。

好吧,除了巨大的缺点和不起作用的事实外,lambda触发方法也让人感到完全过头了。

更新:我不知道为什么我以前没有看到它,但是Amplify文档中有一个Cognito Post Authentication Lambda Trigger,可以准确地说明如何自定义withAuthenticator 。但是,我不想像示例中那样覆盖render(),而是覆盖signIn()(或者我相信)。我已经成功实现了将代码发送到带有适当标头的http://mybackend.mydomain.com/login以便登录后端的代码,但是我似乎无法弄清楚在哪里/如何调用该代码。

我从上面链接的Amplify文档中复制了代码,查看了SignIn section和{{rendered /“ built”?)版本在我的本地源代码文件夹中的{{ 1}},并尝试了以下方法:

node_modules/aws-amplify-react/dist/Auth/SignIn.js

但是所有这些使我得到的是一个空白页面,并且日志中没有任何消息。

新问题:我如何实现class MySignIn extends SignIn { async signIn() { console.log('MySignIn.signIn() start'); super.signIn() .then(data => console.log(data)) .catch(err => console.log(err)); console.log('MySignIn.signIn() end'); } } 以便完成所有MySignIn的工作,但是成功登录后,我还需要其他工作吗?

非常感谢您的考虑! :-)

1 个答案:

答案 0 :(得分:1)

我检查了代码,signIn函数似乎很难扩展,因为它不返回任何内容,因此使用superthen没有意义,因为解析函数是'不会接收任何数据。这就是为什么您的日志为空。要使用它,您需要从头开始重新定义它。

您可以做的是重新实现changeState方法本身,在这种情况下,您可以只调用父方法,然后再做任何您想做的事。

但是仅扩展任何Auth组件就有一个问题,因为如果您想重新实现rendershowComponent函数 对它们进行子类化是因为父级对象(因为父级对象现在被隐藏了)不会返回任何内容。 (尽管在示例中render函数已被明确地重新定义,但这可能是他们应该在文档中清除的。)

在不返回空白页的情况下调用父类的showComponent方法的一种简单方法是从每个组件接收的隐藏组件列表中删除父类。

因此,与changeState方法的扩展一起,看起来像这样:

class MySignIn extends SignIn {
  showComponent(theme) {
    const signIn = this.props.hide.indexOf(SignIn)
    this.props.hide.splice(signIn, 1) // make sure SignIn is not hidden
    return super.showComponent(theme) // call showComponent from SignIn
  }
  changeState(state, data) {
    super.changeState(state, data)
    if (state !== 'signedIn') return
    console.log(data)
    // make the request to the backend
  }
}

现在,您可以像在文档中显示的那样完全通过MySignIn

请记住,更改props应该是一种反模式,但是我还没有找到不涉及重新定义showComponent(或更糟的是{{1 }})方法,因为它是在父级中寻找的。

PR的想法可能是使这些方法(例如render)更易于扩展。

旧答案:

之所以无法实现,是因为在实际实例化组件时,signIn属性会被覆盖。

另一种选择是将函数传递给onStateChange作为登录组件的道具,并检查onStateChange状态,如下所示:

signedIn

根据您对function onStateChange(state, data) { if (state !== 'signedIn') return console.log(data) // do the request to the backend here } 的自定义

withAuthenticator
相关问题