Eag*_*eak 60 authentication amazon-ec2 amazon-ecs jwt amazon-cognito
我正在构建一个由Angular2单页面应用程序和在ECS上运行的REST API组成的系统.API在.Net/Nancy上运行,但这可能会发生变化.
我想尝试一下Cognito,这就是我想象的身份验证工作流程:
我的问题是关于第3步.我的服务器(或者更确切地说:我的无状态,自动扩展,负载平衡的Docker容器)如何验证令牌是否可信?由于"服务器"还没有出台的智威汤逊本身,它不能使用自己的秘密(如在基本JWT例如描述这里).
我已经阅读了Cognito文档并搜索过很多内容,但是我找不到任何关于如何在服务器端使用JWT的好指南.
Eag*_*eak 31
事实证明我没有正确阅读文档.这里解释了(向下滚动到"在Web API中使用ID令牌和访问令牌").
API服务可以下载Cognito的秘密并使用它们来验证收到的JWT.完善.
编辑
@Groady的评论很明确:但你如何验证令牌?我会说使用经过实战考验的库,比如jose4j或nimbus(都是Java),并且不要自己从头开始实施验证.
这是使用nimbus的Spring Boot的一个示例实现,当我最近不得不在java/dropwizard服务中实现它时,让我开始了.
Fac*_*alm 22
这是验证NodeJS上签名的方法:
var jwt = require('jsonwebtoken');
var jwkToPem = require('jwk-to-pem');
var pem = jwkToPem(jwk);
jwt.verify(token, pem, function(err, decoded) {
console.log(decoded)
});
// Note : You can get jwk from https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json
Run Code Online (Sandbox Code Playgroud)
Ott*_*tto 21
AWS 专门为此目的发布了一个 JavaScript 库: https: //github.com/awslabs/aws-jwt-verify。
\n该库与此处提到的其他库具有类似的机制,例如自动下载和缓存 JWKS(可以验证 Cognito JWT 的公钥)。它是用纯 TypeScript 编写的,并且有 0 个依赖项。
\nimport { CognitoJwtVerifier } from "aws-jwt-verify";\n\n// Verifier that expects valid access tokens:\nconst verifier = CognitoJwtVerifier.create({\n userPoolId: "<user_pool_id>",\n tokenUse: "access",\n clientId: "<client_id>",\n});\n\ntry {\n const payload = await verifier.verify(\n "eyJraWQeyJhdF9oYXNoIjoidk..." // the JWT as string\n );\n console.log("Token is valid. Payload:", payload);\n} catch {\n console.log("Token not valid!");\n}\n
Run Code Online (Sandbox Code Playgroud)\n(顺便说一句,该库还包括一个适用于 Cognito 之外的其他身份提供者的类)
\n免责声明:我是该库的作者之一。我们期待客户反馈\xe2\x80\x93\xe2\x80\x93,请给我们留下 GitHub 问题。
\nGau*_*ain 10
Short answer:
You can get the public key for your user pool from the following endpoint:
https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json
If you successfully decode the token using this public key then the token is valid else it is forged.
Long answer:
After you successfully authenticate via cognito, you get your access and id tokens. Now you want to validate whether this token has been tampered with or not. Traditionally we would send these tokens back to the authentication service (which issued this token at the first place) to check if the token is valid. These systems use symmetric key encryption
algorithms such as HMAC
to encrypt the payload using a secret key and so only this system is capable to tell if this token is valid or not.
Traditional auth JWT token Header:
{
"alg": "HS256",
"typ": "JWT"
}
Run Code Online (Sandbox Code Playgroud)
请注意,此处使用的加密算法是对称的 - HMAC + SHA256
但现代身份验证系统(如 Cognito)使用asymmetric key encryption
诸如RSA
使用一对公钥和私钥对有效负载进行加密的算法。有效载荷使用私钥加密,但可以通过公钥解码。使用这种算法的主要优点是我们不必请求单个身份验证服务来判断令牌是否有效。由于每个人都可以访问公钥,因此任何人都可以验证令牌的有效性。验证负载相当分散,没有单点故障。
Cognito JWT 令牌标头:
{
"kid": "abcdefghijklmnopqrsexample=",
"alg": "RS256"
}
Run Code Online (Sandbox Code Playgroud)
本例使用的非对称加密算法——RSA + SHA256
max*_*x_i 10
cognito-jwt-verifier是一个小型 npm 包,用于验证 ID 并访问从节点/Lambda 后端中的 AWS Cognito 获取的 JWT 令牌,依赖性最小。
免责声明:我是本文的作者。我想出它是因为我找不到任何可以为我检查所有方框的东西:
用法(请参阅 github 存储库以获取更详细的示例):
const { verifierFactory } = require('@southlane/cognito-jwt-verifier')
const verifier = verifierFactory({
region: 'us-east-1',
userPoolId: 'us-east-1_PDsy6i0Bf',
appClientId: '5ra91i9p4trq42m2vnjs0pv06q',
tokenType: 'id', // either "access" or "id"
})
const token = 'eyJraWQiOiI0UFFoK0JaVE...' // clipped
try {
const tokenPayload = await verifier.verify(token)
} catch (e) {
// catch error and act accordingly, e.g. throw HTTP 401 error
}
Run Code Online (Sandbox Code Playgroud)
我遇到了类似的问题但没有使用API网关.在我的情况下,我想验证通过AWS Cognito Developer Authenticated身份路由获得的JWT令牌的签名.
就像在各个站点上的许多海报一样,我无法拼凑出我需要在外部验证AWS JWT令牌的签名的位,即服务器端或通过脚本
我想我已经弄明白了,并提出了一个要点来验证AWS JWT令牌签名.它将从PyCrypto中的Crypto.Signature验证带有pyjwt或PKCS1_v1_5c的AWS JWT/JWS令牌
所以,是的,在我的情况下这是python,但它在节点中也很容易实现(npm install jsonwebtoken jwk-to-pem request).
我试图在评论中突出一些问题,因为当我试图解决这个问题时,我主要是做正确的事,但有一些细微差别,比如python dict排序,或缺少和json表示.
希望它可以在某个地方帮助某人.
执行授权码授予流程
假设您:
能够通过以下方式注册/登录并获得访问代码:
https://<your-domain>.auth.us-west-2.amazoncognito.com/login?response_type=code&client_id=<your-client-id>&redirect_uri=<your-redirect-uri>
Run Code Online (Sandbox Code Playgroud)您的浏览器应重定向到 <your-redirect-uri>?code=4dd94e4f-3323-471e-af0f-dc52a8fe98a0
现在,您需要将该代码传递给后端,并让它为您请求令牌。
POST https://<your-domain>.auth.us-west-2.amazoncognito.com/oauth2/token
Authorization
头Basic
和使用username=<app client id>
以及password=<app client secret>
每个在AWS Cognito配置您的应用程序客户端grant_type=authorization_code
code=<your-code>
client_id=<your-client-id>
redirect_uri=<your-redirect-uri>
如果成功,则后端应收到一组base64编码的令牌。
{
id_token: '...',
access_token: '...',
refresh_token: '...',
expires_in: 3600,
token_type: 'Bearer'
}
Run Code Online (Sandbox Code Playgroud)
现在,根据文档,您的后端应通过以下方法验证JWT签名:
由于AWS Cognito为每个用户池生成两对RSA加密密钥,因此您需要确定使用哪个密钥来加密令牌。
这是一个演示如何验证JWT 的NodeJS代码段。
import jsonwebtoken from 'jsonwebtoken'
import jwkToPem from 'jwk-to-pem'
const jsonWebKeys = [ // from https://cognito-idp.us-west-2.amazonaws.com/<UserPoolId>/.well-known/jwks.json
{
"alg": "RS256",
"e": "AQAB",
"kid": "ABCDEFGHIJKLMNOPabc/1A2B3CZ5x6y7MA56Cy+6ubf=",
"kty": "RSA",
"n": "...",
"use": "sig"
},
{
"alg": "RS256",
"e": "AQAB",
"kid": "XYZAAAAAAAAAAAAAAA/1A2B3CZ5x6y7MA56Cy+6abc=",
"kty": "RSA",
"n": "...",
"use": "sig"
}
]
function validateToken(token) {
const header = decodeTokenHeader(token) // {"kid":"XYZAAAAAAAAAAAAAAA/1A2B3CZ5x6y7MA56Cy+6abc=", "alg": "RS256"}
const jsonWebKey = getJsonWebKeyWithKID(header.kid)
verifyJsonWebTokenSignature(token, jsonWebKey, function(err, decodedToken) {
if (err) {
console.error(err)
} else {
console.log(decodedToken)
}
})
}
function decodeTokenHeader(token) {
const [headerEncoded] = token.split('.')[0]
const buff = new Buffer(headerEncoded, 'base64')
const text = buff.toString('ascii')
return JSON.parse(text)
}
func getJsonWebKeyWithKID(kid) {
for (let jwk of jsonWebKeys) {
if (jwk.kid == kid) {
return jwk
}
}
return null
}
function verifyJsonWebTokenSignature(token, jsonWebKey, clbk) {
const pem = jwkToPem(jsonWebKey)
jsonwebtoken.verify(token, pem, { algorithms: ['RS256'] }, function(err, decodedToken) {
return clbk(err, decodedToken)
})
}
validateToken('xxxxxxxxx.XXXXXXXX.xxxxxxxx')
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
29524 次 |
最近记录: |