React+AWS Cognito教程五:使用Cognito保护Lambda/APIGateway


在上几篇文章介绍了如何注册,配置AWS Cognito User Pool,用户登录,Cognito中的Session,如何注销用户的登录,实现更改密码功能,如何Cognito中的用户自定义属性。下面介绍如何通过AWS Cognito UserPool来保护APIGateway。

AWS Cognito

AWS Cognito系列教程:

生成Lambda

首先通过serverless生成一个项目:

mkdir demo
cd demo
sls create --template aws-nodejs

添加依赖:

npm i lodash

更新serverless.yml:

service: random-number-service

frameworkVersion: '2'

provider:
  name: aws
  runtime: nodejs14.x
  region: eu-west-1
  lambdaHashingVersion: 20201221

functions:
  randomAPI:
    handler: handler.random
    events:
      - http:
          path: /random_number
          method: get  
          cors: true

更新handler.js:

'use strict';
const _ = require("lodash"); 

module.exports.random = async (event) => {
  return {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*', 
      'Access-Control-Allow-Credentials': true 
    },
    body: JSON.stringify(
      {
        random_number: _.random(10)
      },
      null,
      2
    ),
  };
};

部署:

sls deploy

然后通过浏览器访问API地址,就可以得到类似这样的输出:

{
  "random_number": 4
}

在AWS配置Lambda/APIGateway和Cognito之间的授权

以下操作也可以通过serverless来定义,但为了直观,这里通过手工操作。

创建authorizer

选择AWS API Gateway -> APIs -> dev-random-number -> Authorizers -> “Create New Authorizer”。

进行如下配置后创建Authorizer:

AWS Cognito

为API Gateway添加authorizer

选择API Gateway后单击要被保护的方法:

AWS Cognito

然后选择刚刚创建的Authorizer:

AWS Cognito

都修改完毕后需要重新部署API:

AWS Cognito

测试受保护的API

现在直接访问这个API的话会返回非授权访问的错误:

AWS Cognito

也就是说,需要找到这个token并将其加入header后才能成功调用API。

使用JWT token:

更新Accounts.js

更新Accounts.js,在调用resolve方法前:

const token = session.getIdToken().getJwtToken()

resolve({
  user,
  headers: {
    Authorization: token,
  },
  ...session,
  ...attributes
});

人工测试

也可以加一个console.log语句输出token的值,之后拿着token就可以在Postman中测试了:

AWS Cognito

在React中访问受保护的API

添加依赖:

npm i axios

添加一个文件RandomNumber.js:

import React, { useState, useContext } from 'react'
import axios from 'axios'

import { AccountContext } from './Accounts'

export default () => {
  const [number, setNumber] = useState(0)

  const { getSession } = useContext(AccountContext)

  const fetchNumber = () => {
    getSession().then(async ({ headers }) => {
      const url = 'https://XXXXXX.execute-api.eu-west-1.amazonaws.com/dev/random_number'
      const resp = await axios.get(url, { headers })
      setNumber(resp.data["random_number"])
    })
  }

  return (
    <div>
      <div>Current number: {number}</div>
      <button onClick={fetchNumber}>Next number</button>
    </div>
  )
}

文章作者: 逻思
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 逻思 !
  目录