Serverless 入门(九)- 权限

Serverless 的权限设计跟 Node.js 项目权限大同小异,比如:AWS 的 Cognito,OAuth2、Cookies 和今天主要讲的 JWT。

JWT 是 JSON Web Token 缩写,详细解释请见 JSON Web Token 入门教程

一、安装

yarn add jsonwebtoken,安装好后,package.json 中添加如下依赖:

  "dependencies": {
    ...
   "jsonwebtoken": "^8.5.1",
    ...
  },

二、封装 JWT

jwt-tools.ts

import { sign, SignOptions, verify } from 'jsonwebtoken';

const saltSecret: string | Buffer = '1234567890';

const jwtSign = (payload: object) => {
  const secretOrPrivateKey: string | Buffer | { key: string; passphrase: string } = saltSecret;
  // Eg: 60, "2 days", "10h", "7d" */
  const options: SignOptions = { expiresIn: '7d' };
  const result: string = sign(payload, secretOrPrivateKey, options);
  return result;
};

const jwtVerify = (token: string) => {
  const secretOrPrivateKey: string | Buffer | { key: string; passphrase: string } = saltSecret;
  try {
    const result: object | string = verify(token, secretOrPrivateKey);
    return result;
  } catch (e) {
    console.error('jwtVerify error:', e);
    return null;
  }
};

export { jwtSign, jwtVerify };

三、引用

import { APIGatewayProxyHandler } from 'aws-lambda';
import 'source-map-support/register';
import { jwtVerify } from './jwt-tools';
3.1 获取 Token
// post
// {"name": "Kenny锅","password": "123456"}
export const login: APIGatewayProxyHandler = async event => {
  const { body = '' } = event;
  if (!body) {
    return { statusCode: 400, body: JSON.stringify({ token: '', message: 'body is empty' }) };
  }

  const { name, password } = JSON.parse(body);
  if (!(name === 'Kenny锅' && password === '123456')) {
    return { statusCode: 403, body: JSON.stringify({ token: '', message: 'name, password is invalid' }) };
  }

  const token = jwtSign({ name, password });
  return {
    statusCode: 200,
    body: JSON.stringify({ token }),
  };
};
3.2 刷新 Token
// post
// {"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS2VubnnplIUiLCJwYXNzd29yZCI6IjEyMzQ1NiIsImlhdCI6MTU1NDYzNDA4MywiZXhwIjoxNTU1MjM4ODgzfQ.5cAjWkM39t5XbWX-b0HxfzbqE0kTP2Zg4BYMUD-VegA"}
export const refresh: APIGatewayProxyHandler = async event => {
  const { body = '' } = event;
  if (!body) {
    return { statusCode: 400, body: JSON.stringify({ token: '', message: 'body is empty' }) };
  }

  const { token } = JSON.parse(body);
  if (!token) {
    return { statusCode: 401, body: JSON.stringify({ token: '', message: 'token is empty' }) };
  }

  const result: object | string = jwtVerify(token);
  if (!result) {
    return { statusCode: 403, body: JSON.stringify({ token: '', message: 'original token expire' }) };
  }

  const { name, password } = result;
  if (!name || !password) {
    return { statusCode: 403, body: JSON.stringify({ token: '', message: 'original data unavailable' }) };
  }

  const newToken = jwtSign({ name, password });
  return { statusCode: 200, body: JSON.stringify({ token: newToken }) };
};

四、获取「用户信息」

import { APIGatewayProxyHandler } from 'aws-lambda';
import 'source-map-support/register';
import { jwtVerify } from './jwt-tools';

// post
// {"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiS2VubnnplIUiLCJwYXNzd29yZCI6IjEyMzQ1NiIsImlhdCI6MTU1NDYzNDA4MywiZXhwIjoxNTU1MjM4ODgzfQ.5cAjWkM39t5XbWX-b0HxfzbqE0kTP2Zg4BYMUD-VegA"}
export const useInfo: APIGatewayProxyHandler = async event => {
  const { body } = event;
  if (!body) {
    return { statusCode: 400, body: JSON.stringify({ data: null, message: 'body is empty' }) };
  }

  const { token } = JSON.parse(body);
  if (!token) {
    return {
      statusCode: 401,
      body: JSON.stringify({ data: null, message: 'token is unavailable' }),
    };
  }

  const result = jwtVerify(token);
  if (!result) {
    return {
      statusCode: 403,
      body: JSON.stringify({ data: null, message: 'token expire' }),
    };
  }

  const { name, exp } = result;
  const data = name ? { name, expired: exp } : null;
  return {
    statusCode: 200,
    body: JSON.stringify({ data }),
  };
};

五、配置 serverless.yml

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          method: get
          path: hello
  login:
    handler: src/auth.login
    events:
      - http:
          method: post
          path: login
  refresh:
    handler: src/auth.refresh
    events:
      - http:
          method: post
          path: refresh-token
  userInfo:
    handler: src/user-info.useInfo
    events:
      - http:
          method: post
          path: user-info

六、 调试代码

6.1 登录
6.2 获取用户信息
6.3 用户快过期了,就调用 refresh 方法

七、完整代码

https://github.com/Kennytian/learning-serverless/tree/master/helloAuthorize

相关文章
  • Serverless 入门(一) - 创建 IAM https://www.jianshu.com/p/9fb731a799e2
  • Serverless 入门(二) - HelloWord https://www.jianshu.com/p/ddf2ffda5f63
  • Serverless 入门(三)- 初始项目解读 https://www.jianshu.com/p/8baba2a8fe9f
  • Serverless 入门(四)- 如何调试 https://www.jianshu.com/p/58d30915de8a
  • Serverless 入门(五)- 常用命令 https://www.jianshu.com/p/28f001ea9d9d
  • Serverless 入门(六)- DynamoDB 数据库(上) https://www.jianshu.com/p/c313b61d1cbf
  • Serverless 入门(七)- DynamoDB 数据库(中) https://www.jianshu.com/p/05e7f4ccd6fe
  • Serverless 入门(八)- DynamoDB 数据库(下) https://www.jianshu.com/p/0f9f1561ec46
  • Serverless 入门(九)- 权限 https://www.jianshu.com/p/97228749d761

你可能感兴趣的:(Serverless 入门(九)- 权限)