运用 Authing + Lambda 替换 AWS Cognito

Amazon Web Services(AWS) 虽然作为市场份额环球第一的云盘算厂商,其产物也不是十全十美的,Cognito (AWS 的身份认证处理方案)及其附带的中文文档就是一个反面教材,其难用水平怒不可遏。固然,除了不轻易用以外,另有接见速率迟缓,不适用于中国市场等题目存在。

而国产的 Authing 能够处理运用 Cognito 的诸多题目,先看一下 Authing 的引见:

Authing 是一个身份认证效劳商,其供应了企业级身份认证和治理处理方案,客户散布教诲、IoT、互联网和电商等多个行业。

Lambda 是一个由 AWS 供应的 Function-as-a-Service (FaaS) 平台 。Lambda 和 AWS 生态连系的异常严密,接入 Lambda 后,开发者能够运用 AWS 生态内的一切资本。比方,我们能够建立一个 Lambda 函数,让用户经由过程 Cognito 登录(固然这篇文章是让用户运用 Authing 登录),然后再挪用别的一个能够上传文件到 S3(AWS 的存储效劳) 的 Lambda 函数。

这类平台(如今多被称为 Serverless,无效劳器架构)的一个优点是能够让开发者无需忧郁基础设施,用心营业研发。

FaaS 或者说 Serverless 平台正在逐步取得市场关注,由于这类范例的平台能够让开发者不必再关注基础设施。”What is serverless” 这篇文章细致的讲解了什么是「无效劳器盘算」和「无效劳器盘算」的优点,引荐读一下。

这篇文章的重要目标是引见怎样运用 Authing + Lambda 替换 AWS Cogito,点击这里体验终究 demo。

《运用 Authing + Lambda 替换 AWS Cognito》

另外,Authing 遵照 OIDC 范例,所以本篇文章将运用 OIDC 来做认证,假如你还不相识什么是 OIDC,请检察这篇文章。

起首确认下用户的操纵流程:

  1. 翻开页面:https://sample.authing.cn/aws/
  2. 点击 Login 举行登录,此时跳转到 Authing 的登录页面(运用的二级域名);
  3. 输入账号密码举行登录,若没有账号密码请先举行注册;
  4. 登录胜利后返回第一步翻开的页面,并显现登录用户的头像;
  5. 此时用户能够看到从 AWS Lambda 要求返来的 Private 信息;

终究效果以下图所示:

《运用 Authing + Lambda 替换 AWS Cognito》

点击这里体验 DEMO

建立一个 Authing 运用

假如你还没有注册 Authing,那末请点击这里举行注册,注册完成后,按以下步骤建立一个 Authing 运用。

  1. 建立运用

《运用 Authing + Lambda 替换 AWS Cognito》

  1. 填写基础信息,运用范例挑选 Web 运用

《运用 Authing + Lambda 替换 AWS Cognito》

  1. 建立完成后会进入到运用主页(一无一切)

《运用 Authing + Lambda 替换 AWS Cognito》

建立 OIDC 运用

建立完运用后相当于你有了一个用户池,接下来你能够建立 OIDC 运用来受权其他顺序(你自身写的或其他第三方顺序)接见你的用户池。

假如你还不清晰什么是 OIDC,请参考这篇文章

  1. 点击「第三方登录」最先建立 OIDC 运用

《运用 Authing + Lambda 替换 AWS Cognito》

  1. 挑选「OIDC 运用」选项卡,并点击「建立 OIDC 运用」

《运用 Authing + Lambda 替换 AWS Cognito》

  1. 填写运用名和认证地点,并勾选 id_token token

《运用 Authing + Lambda 替换 AWS Cognito》

这里要申明一下,建立 OIDC 运用时的认证地点将由 Authing 天生一个二级域名(支撑 HTTPS),且不能反复,回调 URL 填写你自身的回调地点即可,在这里我用的是 https://authing.cn,注重,OIDC 协定中不允许回调 URL 为 localhost,请运用代办东西举行调试。

点击确认,就能够看到我们有了第一个基于 OIDC 协定的受权运用
《运用 Authing + Lambda 替换 AWS Cognito》

建立完成后你能够接见 lambda.authing.cn ,此时会看到报了一个错,别畏惧,这是由于我们提议的受权链接不准确。
《运用 Authing + Lambda 替换 AWS Cognito》

提议准确受权要求的体式格局请继承往下看。

提议受权要求

和绝大多数的 OAuth 运用差不多,OIDC 的受权链接也须要拼接(假如你开发过微信运用,应当会很轻易明白),Authing OIDC 运用的受权链接相符标准范例,详细花样为:

https://lambda.authing.cn/oau…;运用 ID>&redirect_uri=<回调 URL,必需和平台设置完全一样>&scope=openid profile&response_type=<OIDC 形式,分为好几种>&state=<一个随机字符串,用来提防 CSRF 进击>

若须要检察细致的参数,请点击这里检察

比方:

https://lambda.authing.cn/oau…://authing.cn&scope=openid profile&response_type=id_token token&state=jacket

为了简朴起见,这里我们的 response_type 设置为「id_token token」,如许不须要运用「code」调换 token,token 会直接附带到回调地点中。

《运用 Authing + Lambda 替换 AWS Cognito》

假如你的受权链接准确,应当能够看到上图如许的登录窗口,同时这个窗口也是你的终端用户所运用的窗口,他们都将从这里登录然后回调到你设置好的回调 URL 中。

你能够试着注册一个账号然后举行登录,登录完成后能够在掌握台中观察到登录状态。

  1. 注册胜利

《运用 Authing + Lambda 替换 AWS Cognito》

  1. 登录以后的受权页面

《运用 Authing + Lambda 替换 AWS Cognito》

  1. 掌握台中观察到的用户数据

《运用 Authing + Lambda 替换 AWS Cognito》

在你登录胜利后应当会看到回调到了你填写 URL 中,而且附带了许多参数,接下来我们会论述怎样运用这些参数。

猎取用户信息
回调到在掌握台中设置的 redirect_uri 中后,将附带以下信息:

{
    "id_token": "JWT_TOKEN",
    "access_token": "JWT_TOKEN",
    "expires_in": "3600",
    "token_type": "Bearer",
    "state": "jacket",
    "session_state": "644d7b324ba61d517fdedd28b5b6e365d78f2a8178f2ee742474d5b57a99eb3f"
}

能够看到个中包括了 access_token 和 id_token,个中 access_token 能够协助你从 Authing 后端猎取用户信息,而 id_token 中包括了基础的信息,假如你要猎取用户的头像,那末是须要经由过程 access_token 猎取的。

我们先看一个 id_token 的例子:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiI1Y2MyYTg1MTFiYmFmMDRmOTNjZTQ4OWYiLCJub25jZSI6IjE4MzEyODkiLCJzaWQiOiI5MzkwZDA1ZC01ZTM3LTQ3ZWUtODJjNi1jNTQ1ZjA2ODhhMDAiLCJhdF9oYXNoIjoiNmxZMGRXajZYUTY0aExWdHAtR2tEdyIsInNfaGFzaCI6IlZVOU5QYV9JQ0VTSEdxRmxUZ3A2LUEiLCJhdWQiOiI1Y2MyYjU0OGQxNGM3NDJkYjg5M2JhNTUiLCJleHAiOjE1NTYzNjY0ODksImlhdCI6MTU1NjM2Mjg4OSwiaXNzIjoiaHR0cHM6Ly9vYXV0aC5hdXRoaW5nLmNuL29hdXRoL29pZGMifQ.Qc_OMqMf6_wwzW2SsEgEtiaGr3ZY1FWHnRrMU2M7LADGlNpq_pvPrFxAVsR2j-BFr1y48M-Trvq6yAu4_ZOUBHPtIIpoQ5W2bnABytUV693ZcwNlf9CCiLc-k0LG3o1U-BmiH3L6NAV7aKGsfVHS8toiNbVDuimPVdYJsRrF2C1jj1meM1K8FBVwqozXm6YtB--u3sqY4IszHnd5PMEWguLsOkpZJIh7xWeYPpVQ5WKfx0cA8rB_T2puSCbeaUVhgIwNADy06qBqXhUOiA4gdcNbHtx7tvGZMxzMC3rdjpXoZk89Duh3O5tHlMtaBlidJGYavUSjVl7potESecSlBg

运用 jwt.io 剖析后将获得以下效果:

{
  "sub": "5cc2a8511bbaf04f93ce489f",
  "nonce": "1831289",
  "sid": "9390d05d-5e37-47ee-82c6-c545f0688a00",
  "at_hash": "6lY0dWj6XQ64hLVtp-GkDw",
  "s_hash": "VU9NPa_ICESHGqFlTgp6-A",
  "aud": "5cc2b548d14c742db893ba55",
  "exp": 1556366489,
  "iat": 1556362889,
  "iss": "https://oauth.authing.cn/oauth/oidc"
}

个中包括了签发时候(iat)、逾期时候(exp)等字段,能够用来推断用户有无被认证过,在 OIDC 的范例中,JWT 运用 OIDC 运用的 secret 签发,须要开发者在后端考证(这一步我们将会在 Lambda 中实行)后继承实行开发者自身的营业流程。

再来看看 access_token 的例子:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJqdGkiOiJza0p-bTNaYmZsTjVxVGEzR2J2YlMiLCJzdWIiOiI1Y2MyYTg1MTFiYmFmMDRmOTNjZTQ4OWYiLCJpc3MiOiJodHRwczovL29hdXRoLmF1dGhpbmcuY24vb2F1dGgvb2lkYyIsImlhdCI6MTU1NjM2Mjg4OSwiZXhwIjoxNTU2MzY2NDg5LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIiwiYXVkIjoiNWNjMmI1NDhkMTRjNzQyZGI4OTNiYTU1In0.Uf3YK4D9HL-G71hkA4cWt5kitDo5rNgwVA9Vqlv4RjAILNDTylYWtkacKJpLcOSS81ivaNpDVNYYzBSoyN-eMH80VhArPUre74F9SHdonA-IVFVPT0DHRtOAJI9kqDW4tgTXhZeZMUm-MCjVjR-q8XrayXaqrC5Hu5W3D1N-K_jZOlwxzIBf51nuC4NMvSI_wPpYj2WPzGxFwpfTCEbnhj5RO0CcThRpC3EdmpbtcJqStd7AZQhkLyTb1TQLHJOel8DSxLnLnoIU0rZXsodK6EjE_oqRLagetNXF1cKfRmnGFaAKZKqgvHc527S_CVkgXIwcHBRmDeqo93CCId_hmQ

运用 jwt.io 剖析后将获得以下效果:

{
  "jti": "skJ~m3ZbflN5qTa3GbvbS",
  "sub": "5cc2a8511bbaf04f93ce489f",
  "iss": "https://oauth.authing.cn/oauth/oidc",
  "iat": 1556362889,
  "exp": 1556366489,
  "scope": "openid profile",
  "aud": "5cc2b548d14c742db893ba55"
}

能够看到 access_token 比拟 id_token 是少了许多信息的,这里有一段英文的引见,该引见讲解了 access_token 和 id_token 的区分:

ID Tokens vs Access Tokens. The ID Token is a security token granted by the OpenID Provider that contains information about an End-User. This information tells your client application that the user is authenticated, and can also give you information like their username or locale.You can pass an ID Token around different components of your client, and these components can use the ID Token to confirm that the user is authenticated and also to retrieve information about them.Access tokens, on the other hand, are not intended to carry information about the user. They simply allow access to certain defined server resources. More discussion about when to use access tokens can be found in Validating Access Tokens.

简朴来说,id_token 通知你用户被考证过了,而 access_token 是一个你能够接见资本效劳器(这里就是 Authing) 的一个凭据。

同时也能够看到,idtoken 包括的信息较少,假如想猎取更多信息,须要运用 access_token 来猎取。猎取体式格局也异常简朴,只须要往以下链接发送 GET 要求而且附带 access_token 即可,如:

$ curl https://users.authing.cn/oauth/oidc/user/userinfo?access_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQy...balabala...verylong...

能够猎取到 id 等信息,猎取到 id 以后你能够将 id 存储到你自身的数据库中以完成自身的现实营业。

{
    "sub":"5cc2a8511bbaf04f93ce489f",
    "nickname":"",
    "picture":"https://usercontents.authing.cn/authing-avatar.png"
}

上面的 JSON 是一个运用 access_token 调换用户数据后的返回效果。

好了,如今我们已猎取到 Token 了,接下来我们须要在 Lambda 中考证这个 Token 的合法性并在前端显现差别的信息。

编写 Lambda 函数

编写 Lambda 函数引荐运用 Serverless 这个 CLI,AWS 掌握台中的函数编写可谓让人痛不欲生。

同时,你能够到这里检察完全代码

Lambda 在这篇文章中重要用来做三件事:

  1. 对 id_token 举行认证,以猎取用户是不是被认证过;
  2. 供应一个 Public API,此 API 能够直接被接见;
  3. 供应一个 Private API,此 API 须要经由认证后被接见;

对 id_token 举行认证

认证 id_token 起首须要晓得 OIDC 运用的 secret,此值能够在 Authing 掌握台检察 OIDC 运用的概况中找到:

《运用 Authing + Lambda 替换 AWS Cognito》

请务必保管好此值,防止向任何人走漏

id_token 在签发时的署名是此 secret ,因此在 JavaScript 中能够直接运用 jsonwebtoken 这个库来考证 id_token 的合法性(概况请参考:考证 Token 合法性)。

在掌握台中装置 jsonwebtoken:

$ npm install jsonwebtoken --save

P.S. 在 lambda 中引入包后会一同打包上传到 AWS Lambda 运转时中。

const jwt = require('jsonwebtoken');

// Policy helper function 
// 这是 AWS 供应的模版代码,这里不须要做修正
const generatePolicy = (principalId, effect, resource) => {
  const authResponse = {};
  authResponse.principalId = principalId;
  if (effect && resource) {
    const policyDocument = {};
    policyDocument.Version = '2012-10-17';
    policyDocument.Statement = [];
    const statementOne = {};
    statementOne.Action = 'execute-api:Invoke';
    statementOne.Effect = effect;
    statementOne.Resource = resource;
    policyDocument.Statement[0] = statementOne;
    authResponse.policyDocument = policyDocument;
  }
  return authResponse;
};

// Reusable Authorizer function, set on `authorizer` field in serverless.yml
module.exports.auth = async (event, context, cb) => {
  if (event.authorizationToken) {
    // remove "bearer " from token
    const token = event.authorizationToken.substring(7);

    try {
        let decoded = jwt.verify(token, 'YOUR_OIDC_APP_SECRET'),
          expired = (Date.parse(new Date()) / 1000) > decoded.exp;
        if (expired) {
          cb('Unauthorized, Login information has expired.');
        }else {
          cb(null, generatePolicy('user', 'Allow', event.methodArn));
        }
      } catch (error) {
        cb('Unauthorized');
      }
  } else {
    cb('Unauthorized');
  }
};

大众 API

// Public API
module.exports.publicEndpoint = (event, context, cb) => {
  cb(null, { message: 'Welcome to our Public API!' });
};

私有 API

// Private API
module.exports.privateEndpoint = (event, context, cb) => {
  cb(null, { message: 'Only logged in users can see this' });
};

serverless.yml

service: serverless-authorizer

provider: 
 name: aws
 runtime: nodejs8.10

functions:
  auth:
    handler: handler.auth
  getUserInfo:
    handler: handler.getUserInfo
    events:
      - http:
          path: api/userInfo
          method: get
          integration: lambda
          cors: true    
  publicEndpoint:
    handler: handler.publicEndpoint
    events:
      - http:
          path: api/public
          method: get
          integration: lambda
          cors: true
  privateEndpoint:
    handler: handler.privateEndpoint
    events:
      - http:
          path: api/private
          method: get
          integration: lambda
          authorizer: auth # See custom authorizer docs here: http://bit.ly/2gXw9pO
          cors: true

此文件可用来设置须要鉴权的路由,如上面代码中的 privateEndpoint,设置了 authorizer 为 auth 函数。

点击此处检察完全代码

测试 Lambda

写完了代码以后我们须要举行测试。

Lambda 支撑直接在当地测试,能够运用以下敕令:

$ sls invoke local -f auth --data '{"authorizationToken": "Bearer <id_token>"}'

假如当地测试返回了以下信息则示意考证胜利:

{
    "principalId": "user"
}

布置 Lambda

$ serverless deploy

布置完成后会获得三个链接,这三个链接分别是上述代码的三个函数。

《运用 Authing + Lambda 替换 AWS Cognito》

红框中的路由是在 serverless.yml 中定义好的,能够直接映射到函数中。

运用 curl 或 postman 将 OIDC 登录后的 id_token 携带到 header 的 Authorization 中即可检察效果,如:

$ curl --header "Authorization: <id_token>" <endpoint>

上述三个路由的效果应当为:

curl <endpoint/dev/api/public> - Should work! Public!
curl <endpoint/dev/api/private> - Should not work
curl --header "Authorization: <id_token>" <endpoint/dev/api/private> - Should work! Authorized!

末了,在我们的前端补充上相干信息,在点击登录后应当能够看到以下信息:

《运用 Authing + Lambda 替换 AWS Cognito》

线上体验地点:https://sample.authing.cn/aws/

Enjoy!
Authing.cn – 抢先的身份认证云

《运用 Authing + Lambda 替换 AWS Cognito》

    原文作者:ivydom
    原文地址: https://segmentfault.com/a/1190000019038342
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞