<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-auth-jwt</artifactId>
<version>5.0.1</version>
</dependency> JWT 身份验证提供程序
此组件包含一个开箱即用的 JWT 实现。要使用此项目,请将以下依赖项添加到构建描述符的 dependencies 部分
-
Maven(在您的
pom.xml中)
-
Gradle(在您的
build.gradle文件中)
compile 'io.vertx:vertx-auth-jwt:5.0.1' JSON Web Token 是一种以明文(通常在 URL 中)发送信息并可验证其内容可信度的简单方式。JWT 非常适合以下场景:
-
在单点登录(Single Sign-On)场景中,您需要一个独立的身份验证服务器,该服务器可以以可信方式发送用户信息。
-
无状态 API 服务器,非常适合单页应用。
-
等等……
在决定使用 JWT 之前,请务必注意 JWT 不会加密有效负载,它只对其进行签名。您不应使用 JWT 发送任何秘密信息,而应发送非秘密但需要验证的信息。例如,发送一个已签名的用户 ID 来指示应登录的用户会非常有效!发送用户密码则会非常、非常糟糕。
其主要优点是
-
它允许您验证令牌的真实性。
-
它有一个 JSON 主体,可以包含您想要的任意数量的数据。
-
它完全无状态。
要创建提供程序实例,您可以使用 JWTAuth。您在 JSON 对象中指定配置。
以下是创建 JWT 身份验证提供程序的一个示例
JWTAuthOptions config = new JWTAuthOptions()
.setKeyStore(new KeyStoreOptions()
.setPath("keystore.jceks")
.setPassword("secret")
.setType("jceks"));
AuthenticationProvider provider = JWTAuth.create(vertx, config); JWT 的典型使用流程是,在您的应用程序中有一个端点用于颁发令牌,此端点应在 SSL 模式下运行,之后您验证请求用户,例如通过其用户名和密码,您可以执行以下操作
JWTAuthOptions config = new JWTAuthOptions()
.setKeyStore(new KeyStoreOptions()
.setPath("keystore.jceks")
.setPassword("secret")
.setType("jceks"));
JWTAuth provider = JWTAuth.create(vertx, config);
// on the verify endpoint once you verify the identity
// of the user by its username/password
if ("paulo".equals(username) && "super_secret".equals(password)) {
String token = provider.generateToken(
new JsonObject().put("sub", "paulo"), new JWTOptions());
// now for any request to protected resources you should
// pass this string in the HTTP header Authorization as:
// Authorization: Bearer <token>
} 加载密钥
加载密钥可以通过 3 种不同的方式进行
-
使用密钥(对称密钥)
-
使用 OpenSSL
pem格式文件(公钥/私钥) -
使用 Java 密钥库文件(对称密钥和公钥/私钥)
使用对称密钥
JWT 的默认签名方法称为 HS256。在此情况下,HS 代表 使用 SHA256 的 HMAC 签名。
这是最简单的加载密钥方式。您只需要一个在您和第三方之间共享的密钥,例如,假设密钥是:keyboard cat,那么您可以将身份验证配置为
JWTAuth provider = JWTAuth.create(vertx, new JWTAuthOptions()
.addPubSecKey(new PubSecKeyOptions()
.setAlgorithm("HS256")
.setBuffer("keyboard cat")));
String token = provider.generateToken(new JsonObject()); 在这种情况下,密钥被配置为公钥,因为它是一个双方都已知的令牌,并且您将您的公钥/私钥配置为对称密钥。
使用 RSA 密钥
本节绝非 OpenSSL 手册,建议阅读 OpenSSL 命令行用法。我们将介绍如何生成最常见的密钥以及如何在 JWT 身份验证中使用它们。
假设您想使用非常常见的 RS256 JWT 算法来保护您的应用程序。与某些看法相反,256 不是密钥长度,而是哈希算法签名长度。任何 RSA 密钥都可以与此 JWT 算法一起使用。下面是一个信息表
| "alg" 参数值 | 数字签名算法 |
|---|---|
RS256 | 使用 SHA-256 的 RSASSA-PKCS1-v1_5 |
RS384 | 使用 SHA-384 的 RSASSA-PKCS1-v1_5 |
RS512 | 使用 SHA-512 的 RSASSA-PKCS1-v1_5 |
如果您想生成一个 2048 位 RSA 密钥对,那么您可以这样做(请记住不要添加密码,否则您将无法在 JWT 身份验证中读取私钥)
openssl genrsa -out private.pem 2048
您可以观察到密钥是正确的,因为文件内容与此类似
-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAxPSbCQY5mBKFDIn1kggvWb4ChjrctqD4nFnJOJk4mpuZ/u3h ... e4k0yN3F1J1DVlqYWJxaIMzxavQsi9Hz4p2JgyaZMDGB6kGixkMo -----END RSA PRIVATE KEY-----
标准 JDK 无法直接读取此文件,因此我们必须首先将其转换为 PKCS8 格式
openssl pkcs8 -topk8 -inform PEM -in private.pem -out private_key.pem -nocrypt
现在,新的文件 private_key.pem(与原始文件相似)包含
-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDE9JsJBjmYEoUM ... 0fPinYmDJpkwMYHqQaLGQyg= -----END PRIVATE KEY-----
如果我们只验证令牌(您只需要 private_key.pem 文件),但在某些时候您也需要颁发令牌,因此您需要一个公钥。在这种情况下,您需要从私钥文件中提取公钥
openssl rsa -in private.pem -outform PEM -pubout -out public.pem
您应该会看到文件内容与此类似
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxPSbCQY5mBKFDIn1kggv ... qwIDAQAB -----END PUBLIC KEY-----
现在您可以使用它来颁发或验证令牌
JWTAuth provider = JWTAuth.create(vertx, new JWTAuthOptions()
.addPubSecKey(new PubSecKeyOptions()
.setAlgorithm("RS256")
.setBuffer(
"-----BEGIN PUBLIC KEY-----\n" +
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxPSbCQY5mBKFDIn1kggv\n" +
"Wb4ChjrctqD4nFnJOJk4mpuZ/u3h2ZgeKJJkJv8+5oFO6vsEwF7/TqKXp0XDp6IH\n" +
"byaOSWdkl535rCYR5AxDSjwnuSXsSp54pvB+fEEFDPFF81GHixepIbqXCB+BnCTg\n" +
"N65BqwNn/1Vgqv6+H3nweNlbTv8e/scEgbg6ZYcsnBBB9kYLp69FSwNWpvPmd60e\n" +
"3DWyIo3WCUmKlQgjHL4PHLKYwwKgOHG/aNl4hN4/wqTixCAHe6KdLnehLn71x+Z0\n" +
"SyXbWooftefpJP1wMbwlCpH3ikBzVIfHKLWT9QIOVoRgchPU3WAsZv/ePgl5i8Co\n" +
"qwIDAQAB\n" +
"-----END PUBLIC KEY-----"))
.addPubSecKey(new PubSecKeyOptions()
.setAlgorithm("RS256")
.setBuffer(
"-----BEGIN PRIVATE KEY-----\n" +
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDE9JsJBjmYEoUM\n" +
"ifWSCC9ZvgKGOty2oPicWck4mTiam5n+7eHZmB4okmQm/z7mgU7q+wTAXv9Oopen\n" +
"RcOnogdvJo5JZ2SXnfmsJhHkDENKPCe5JexKnnim8H58QQUM8UXzUYeLF6khupcI\n" +
"H4GcJOA3rkGrA2f/VWCq/r4fefB42VtO/x7+xwSBuDplhyycEEH2Rgunr0VLA1am\n" +
"8+Z3rR7cNbIijdYJSYqVCCMcvg8cspjDAqA4cb9o2XiE3j/CpOLEIAd7op0ud6Eu\n" +
"fvXH5nRLJdtaih+15+kk/XAxvCUKkfeKQHNUh8cotZP1Ag5WhGByE9TdYCxm/94+\n" +
"CXmLwKirAgMBAAECggEAeQ+M+BgOcK35gAKQoklLqZLEhHNL1SnOhnQd3h84DrhU\n" +
"CMF5UEFTUEbjLqE3rYGP25mdiw0ZSuFf7B5SrAhJH4YIcZAO4a7ll23zE0SCW+/r\n" +
"zr9DpX4Q1TP/2yowC4uGHpBfixxpBmVljkWnai20cCU5Ef/O/cAh4hkhDcHrEKwb\n" +
"m9nymKQt06YnvpCMKoHDdqzfB3eByoAKuGxo/sbi5LDpWalCabcg7w+WKIEU1PHb\n" +
"Qi+RiDf3TzbQ6TYhAEH2rKM9JHbp02TO/r3QOoqHMITW6FKYvfiVFN+voS5zzAO3\n" +
"c5X4I+ICNzm+mnt8wElV1B6nO2hFg2PE9uVnlgB2GQKBgQD8xkjNhERaT7f78gBl\n" +
"ch15DRDH0m1rz84PKRznoPrSEY/HlWddlGkn0sTnbVYKXVTvNytKSmznRZ7fSTJB\n" +
"2IhQV7+I0jeb7pyLllF5PdSQqKTk6oCeL8h8eDPN7awZ731zff1AGgJ3DJXlRTh/\n" +
"O6zj9nI8llvGzP30274I2/+cdwKBgQDHd/twbiHZZTDexYewP0ufQDtZP1Nk54fj\n" +
"EpkEuoTdEPymRoq7xo+Lqj5ewhAtVKQuz6aH4BeEtSCHhxy8OFLDBdoGCEd/WBpD\n" +
"f+82sfmGk+FxLyYkLxHCxsZdOb93zkUXPCoCrvNRaUFO1qq5Dk8eftGCdC3iETHE\n" +
"6h5avxHGbQKBgQCLHQVMNhL4MQ9slU8qhZc627n0fxbBUuhw54uE3s+rdQbQLKVq\n" +
"lxcYV6MOStojciIgVRh6FmPBFEvPTxVdr7G1pdU/k5IPO07kc6H7O9AUnPvDEFwg\n" +
"suN/vRelqbwhufAs85XBBY99vWtxdpsVSt5nx2YvegCgdIj/jUAU2B7hGQKBgEgV\n" +
"sCRdaJYr35FiSTsEZMvUZp5GKFka4xzIp8vxq/pIHUXp0FEz3MRYbdnIwBfhssPH\n" +
"/yKzdUxcOLlBtry+jgo0nyn26/+1Uyh5n3VgtBBSePJyW5JQAFcnhqBCMlOVk5pl\n" +
"/7igiQYux486PNBLv4QByK0gV0SPejDzeqzIyB+xAoGAe5if7DAAKhH0r2M8vTkm\n" +
"JvbCFjwuvhjuI+A8AuS8zw634BHne2a1Fkvc8c3d9VDbqsHCtv2tVkxkKXPjVvtB\n" +
"DtzuwUbp6ebF+jOfPK0LDuJoTdTdiNjIcXJ7iTTI3cXUnUNWWphYnFogzPFq9CyL\n" +
"0fPinYmDJpkwMYHqQaLGQyg=\n" +
"-----END PRIVATE KEY-----")
));
String token = provider.generateToken(
new JsonObject().put("some", "token-data"),
new JWTOptions().setAlgorithm("RS256")); 使用 EC 密钥
也支持椭圆曲线密钥,但默认的 JDK 对可使用的功能有一些限制。
用法与 RSA 非常相似,首先您创建一个私钥
openssl ecparam -name secp256r1 -genkey -out private.pem
所以您会得到类似这样的内容
-----BEGIN EC PARAMETERS----- BggqhkjOPQMBBw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MHcCAQEEIMZGaqZDTHL+IzFYEWLIYITXpGzOJuiQxR2VNGheq7ShoAoGCCqGSM49 AwEHoUQDQgAEG1O9LCrP6hg3Y9q68+LF0q48UcOkwVKE1ax0b56wjVusf3qnuFO2 /+XHKKhtzEavvFMeXRQ+ZVEqM0yGNb04qw== -----END EC PRIVATE KEY-----
然而 JDK 更偏好 PKCS8 格式,所以我们必须进行转换
openssl pkcs8 -topk8 -nocrypt -in private.pem -out private_key.pem
这将为您提供一个类似这样的密钥
-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgxkZqpkNMcv4jMVgR YshghNekbM4m6JDFHZU0aF6rtKGhRANCAAQbU70sKs/qGDdj2rrz4sXSrjxRw6TB UoTVrHRvnrCNW6x/eqe4U7b/5ccoqG3MRq+8Ux5dFD5lUSozTIY1vTir -----END PRIVATE KEY-----
使用私钥您已经可以生成令牌
JWTAuth provider = JWTAuth.create(vertx, new JWTAuthOptions()
.addPubSecKey(new PubSecKeyOptions()
.setAlgorithm("ES256")
.setBuffer(
"-----BEGIN PRIVATE KEY-----\n" +
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgeRyEfU1NSHPTCuC9\n" +
"rwLZMukaWCH2Fk6q5w+XBYrKtLihRANCAAStpUnwKmSvBM9EI+W5QN3ALpvz6bh0\n" +
"SPCXyz5KfQZQuSj4f3l+xNERDUDaygIUdLjBXf/bc15ur2iZjcq4r0Mr\n" +
"-----END PRIVATE KEY-----\n")
));
String token = provider.generateToken(
new JsonObject(),
new JWTOptions().setAlgorithm("ES256")); 因此,为了验证令牌,您将需要一个公钥
openssl ec -in private.pem -pubout -out public.pem
这样您就可以用它执行所有操作
JWTAuth provider = JWTAuth.create(vertx, new JWTAuthOptions()
.addPubSecKey(new PubSecKeyOptions()
.setAlgorithm("ES256")
.setBuffer(
"-----BEGIN PUBLIC KEY-----\n" +
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEraVJ8CpkrwTPRCPluUDdwC6b8+m4\n" +
"dEjwl8s+Sn0GULko+H95fsTREQ1A2soCFHS4wV3/23Nebq9omY3KuK9DKw==\n" +
"-----END PUBLIC KEY-----"))
.addPubSecKey(new PubSecKeyOptions()
.setAlgorithm("ES256")
.setBuffer(
"-----BEGIN PRIVATE KEY-----\n" +
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgeRyEfU1NSHPTCuC9\n" +
"rwLZMukaWCH2Fk6q5w+XBYrKtLihRANCAAStpUnwKmSvBM9EI+W5QN3ALpvz6bh0\n" +
"SPCXyz5KfQZQuSj4f3l+xNERDUDaygIUdLjBXf/bc15ur2iZjcq4r0Mr")
));
String token = provider.generateToken(
new JsonObject(),
new JWTOptions().setAlgorithm("ES256")); JWT 密钥库文件
如果您更喜欢使用 Java 密钥库,那么也可以这样做。
此身份验证提供程序需要在类路径或文件系统中有一个密钥库,其中包含 javax.crypto.Mac 或 java.security.Signature,以便对生成的令牌进行签名和验证。
默认情况下,实现将查找以下别名,但并非所有别名都必须存在。作为一项良好实践,HS256 应该存在。
`HS256`:: HMAC using SHA-256 hash algorithm `HS384`:: HMAC using SHA-384 hash algorithm `HS512`:: HMAC using SHA-512 hash algorithm `RS256`:: RSASSA using SHA-256 hash algorithm `RS384`:: RSASSA using SHA-384 hash algorithm `RS512`:: RSASSA using SHA-512 hash algorithm `ES256`:: ECDSA using P-256 curve and SHA-256 hash algorithm `ES384`:: ECDSA using P-384 curve and SHA-384 hash algorithm `ES512`:: ECDSA using P-521 curve and SHA-512 hash algorithm
如果未提供密钥库,则实现将回退到不安全模式,并且不会验证签名,这对于有效负载已通过外部方式签名和/或加密的情况很有用。
存储在密钥库中的密钥对总是包含一个证书。证书的有效性在加载时进行测试,如果密钥已过期或尚未生效,则不会加载。
所有密钥算法都会检查是否与给定别名匹配。例如,如果 RS256 密钥是使用 EC 算法颁发的,或者使用 RSA 但签名是 SHA1WithRSA 而不是 SHA256WithRSA,则不会加载该密钥。
生成新的密钥库文件
生成密钥库文件唯一需要的工具是 keytool,您现在可以通过运行以下命令指定所需的算法
keytool -genseckey -keystore keystore.jceks -storetype jceks -storepass secret -keyalg HMacSHA256 -keysize 2048 -alias HS256 -keypass secret keytool -genseckey -keystore keystore.jceks -storetype jceks -storepass secret -keyalg HMacSHA384 -keysize 2048 -alias HS384 -keypass secret keytool -genseckey -keystore keystore.jceks -storetype jceks -storepass secret -keyalg HMacSHA512 -keysize 2048 -alias HS512 -keypass secret keytool -genkey -keystore keystore.jceks -storetype jceks -storepass secret -keyalg RSA -keysize 2048 -alias RS256 -keypass secret -sigalg SHA256withRSA -dname "CN=,OU=,O=,L=,ST=,C=" -validity 360 keytool -genkey -keystore keystore.jceks -storetype jceks -storepass secret -keyalg RSA -keysize 2048 -alias RS384 -keypass secret -sigalg SHA384withRSA -dname "CN=,OU=,O=,L=,ST=,C=" -validity 360 keytool -genkey -keystore keystore.jceks -storetype jceks -storepass secret -keyalg RSA -keysize 2048 -alias RS512 -keypass secret -sigalg SHA512withRSA -dname "CN=,OU=,O=,L=,ST=,C=" -validity 360 keytool -genkeypair -keystore keystore.jceks -storetype jceks -storepass secret -keyalg EC -keysize 256 -alias ES256 -keypass secret -sigalg SHA256withECDSA -dname "CN=,OU=,O=,L=,ST=,C=" -validity 360 keytool -genkeypair -keystore keystore.jceks -storetype jceks -storepass secret -keyalg EC -keysize 384 -alias ES384 -keypass secret -sigalg SHA384withECDSA -dname "CN=,OU=,O=,L=,ST=,C=" -validity 360 keytool -genkeypair -keystore keystore.jceks -storetype jceks -storepass secret -keyalg EC -keysize 521 -alias ES512 -keypass secret -sigalg SHA512withECDSA -dname "CN=,OU=,O=,L=,ST=,C=" -validity 360
有关密钥库以及如何使用 PKCS12 格式(Java >=9 默认)的更多信息,请参阅通用模块的文档。
只读令牌
如果您需要使用第三方颁发的 JWT 令牌,您可能没有私钥,在这种情况下,您只需要一个 PEM 格式的公钥。
JWTAuthOptions config = new JWTAuthOptions()
.addPubSecKey(new PubSecKeyOptions()
.setAlgorithm("RS256")
.setBuffer("BASE64-ENCODED-PUBLIC_KEY"));
AuthenticationProvider provider = JWTAuth.create(vertx, config); 使用 JWT 进行身份验证/授权 (AuthN/AuthZ)
在开发微服务等应用程序时,一个常见的场景是您希望您的应用程序能够使用 API。这些 API 并非供人类使用,因此我们应该移除所有交互式的消费者身份验证部分。
在这种场景下,可以使用 HTTP 作为协议来调用此 API,并且 HTTP 协议已经定义了一个 Authorization 头,该头应用于传递授权信息。在大多数情况下,您会看到令牌以不记名令牌(bearer tokens)的形式发送,即:Authorization: Bearer some+base64+string。
身份验证 (AuthN)
对于此提供程序,如果令牌通过签名检查并且未过期,则用户通过身份验证。因此,私钥必须妥善保管,不得在项目之间复制粘贴,否则将存在安全漏洞。
jwtAuth.authenticate(new TokenCredentials("BASE64-ENCODED-STRING"))
.onSuccess(user -> System.out.println("User: " + user.principal()))
.onFailure(err -> {
// Failed!
}); 简而言之,提供程序会检查以下几项
-
令牌签名对内部私钥有效
-
字段:
exp、iat、nbf、audience、issuer根据配置有效
如果所有这些都有效,则令牌被认为是有效的,并返回一个用户对象。
虽然 exp、iat 和 nbf 字段只是简单的时间戳检查,但只有 exp 可以配置为被忽略
JWTAuth jwtAuth = JWTAuth
.create(vertx, new JWTAuthOptions()
.setJWTOptions(new JWTOptions().setIgnoreExpiration(true)));
// This string is what you see after the string "Bearer" in the
// HTTP Authorization header
// In this case we are forcing the provider to ignore the `exp` field
jwtAuth.authenticate(
new TokenCredentials("BASE64-ENCODED-STRING"))
.onSuccess(user -> System.out.println("User: " + user.principal()))
.onFailure(err -> {
// Failed!
}); 为了验证 aud 字段,需要像之前一样传递选项
JWTAuth jwtAuth = JWTAuth
.create(vertx, new JWTAuthOptions()
.setJWTOptions(new JWTOptions().addAudience("my-service")));
// This string is what you see after the string "Bearer" in the
// HTTP Authorization header
// In this case we are forcing the provider to verify the aud field
jwtAuth.authenticate(
new TokenCredentials("BASE64-ENCODED-STRING"))
.onSuccess(user -> System.out.println("User: " + user.principal()))
.onFailure(err -> {
// Failed!
}); 发布者(issuer)也是如此
JWTAuth jwtAuth = JWTAuth
.create(vertx, new JWTAuthOptions()
.setJWTOptions(new JWTOptions().setIssuer("my-corp.com")));
// This string is what you see after the string "Bearer" in the
// HTTP Authorization header
// In this case we are forcing the provider to verify the issuer
jwtAuth.authenticate(
new TokenCredentials("BASE64-ENCODED-STRING"))
.onSuccess(user -> System.out.println("User: " + user.principal()))
.onFailure(err -> {
// Failed!
}); 授权 (AuthZ)
一旦令牌被解析并有效,我们就可以使用它来执行授权任务。最简单的方法是验证用户是否具有特定权限。授权将遵循通用的 AuthorizationProvider API。选择生成您的令牌的提供程序并进行评估。
目前有 2 个工厂
-
JWTAuthorization根据 "permissions" 声明键检查令牌。 -
MicroProfileAuthorization根据 MP JWT 规范检查令牌。
典型的用法是使用提供程序从用户对象中提取权限并执行认证
AuthorizationProvider authz = MicroProfileAuthorization.create();
authz.getAuthorizations(user)
.onSuccess(v -> {
// and now we can perform checks as needed
if (PermissionBasedAuthorization.create("create-report").match(user)) {
// Yes the user can create reports
}
}); 默认情况下,提供程序将在键 permissions 下查找,但与其他提供程序一样,可以使用 : 作为分隔符将概念扩展到权限和角色,因此 role:authority 可用于查找令牌。
由于 JWT 形式自由,并且没有关于在哪里查找声明的标准,因此可以将位置配置为使用 permissions 之外的其他内容,例如,甚至可以在这样的路径下查找
JsonObject config = new JsonObject()
.put("public-key", "BASE64-ENCODED-PUBLIC_KEY")
// since we're consuming keycloak JWTs we need
// to locate the permission claims in the token
.put("permissionsClaimKey", "realm_access/roles");
AuthenticationProvider provider =
JWTAuth.create(vertx, new JWTAuthOptions(config)); 因此,在此示例中,我们将 JWT 配置为与 Keycloak 令牌格式一起使用。在这种情况下,声明将在路径 realm_access/roles 下而不是 permissions 下进行检查。
验证令牌
当调用 authenticate 方法时,令牌会根据初始化期间提供的 JWTOptions 进行验证。验证执行以下步骤
-
如果
ignoreExpiration(默认为 false)为 false,则检查令牌是否过期,这将检查字段:exp、iat和nbf。由于有时时钟不可靠,可以配置一些leeway(宽限时间)应用于日期,这样如果日期超出所需限制,我们允许一定的宽限期。 -
如果提供了
audience,则令牌的aud会与配置的进行检查,并且所有配置的受众都必须在令牌中。 -
如果配置了
issuer,则令牌的iss会与配置的进行检查。
一旦这些验证完成,就会返回一个 JWTUser 对象,该对象配置有对配置中提供的权限声明键的引用。此值稍后在执行授权时使用。该值对应于应检查权限的 JSON 路径。
自定义令牌生成
与令牌验证方式相同,令牌生成也在初始化期间进行初步配置。
生成令牌时,可以提供一个可选的额外参数来控制令牌生成,这是一个 JWTOptions 对象。令牌签名算法(默认为 HS256)可以使用 algorithm 属性进行配置。在这种情况下,会查找与该算法对应的密钥并用于签名。
可以通过使用选项 headers 属性指定任何要与默认头部合并的额外头部来添加令牌头部。
有时,颁发不带时间戳的令牌可能很有用(例如,测试、开发时间),在这种情况下,应将属性 noTimestamp 设置为 true(默认为 false)。这意味着令牌中没有 iat 字段。
令牌过期由属性 expiresInSeconds 控制,默认情况下没有过期。其他控制字段 audience、issuer 和 subject 如果在配置中可用,则会被选中并添加到令牌元数据中。
最后,令牌以正确的格式签名和编码。