25、微服务安全:JWT与MicroProfile JWT的应用

微服务安全:JWT与MicroProfile JWT应用

微服务安全:JWT与MicroProfile JWT的应用

1. JWT签名验证

JWT(Json Web Tokens)是一种用于在网络应用中安全传输信息的开放标准。每个JWT都会使用头部 alg 声明中定义的算法进行签名,以确保其未被篡改。验证JWT签名的一种简单方法是将原始令牌内容粘贴到 https://jwt.io/#encoded-jwt 提供的表单中。具体步骤如下:
1. 将JWT粘贴到编码表单中,此时JWT的头部和有效负载部分将显示声明值。
2. JWT头部:头部声明(尽管值不一定相同)将与特定声明匹配。
3. JWT有效负载:声明(同样值不一定相同)将与另一些特定声明匹配。
4. 由于未提供公钥,签名无法验证。

若要获取公钥,可运行如下命令,输出结果应类似于以下示例:

scripts/createpem.sh

以下是获取到的公钥示例:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjJ/GYpCkgfYT1HYpa96AP8djbKiv25Yh
VlZcHcIt2QX4VZPJM/qntF2m7ubPSz3zHHNQUOWYl+3xIo4EFfCcTPTBgL0aSlCsuT5+0RuajsFj
ejLGa19p3eKuBjtB0buqI4SbxpitvZj4L4beBdFj+r2NZZNxeFFMrd9lORW3b4cUmk8tS6ZrgbTK
Ij3adjlVMYHOkGQNNGBf1KJkdbi8UQtXaATuyFHiQCCYY/ENWGGomu+dXqvqnRRsdWBndsUcCNe+
NPwT1z3lbfYoXkldWFVvXjBnNme/f8mCMWuKBz4fGZUkt7Sdc5FPnFpsbT+0inarxIov3puDxHbB
gNJ9xwIDAQAB
-----END PUBLIC KEY-----

将此公钥粘贴到 jwt.io 表单的公钥字段中,即可完成签名验证。需要注意的是,不同安装环境下的令牌和公钥是不同的,使用示例中的公钥验证其他安装环境下的令牌会失败。

2. JWT有效负载声明

JWT的有效负载包含了一系列声明,以下是一些MicroProfile JWT所需的重要声明:
| 声明 | 描述 |
| ---- | ---- |
| typ | 声明令牌的媒体类型 |
| iss* | MicroProfile JWT的颁发者 |
| sub* | 标识JWT的主体 |
| exp* | JWT的过期时间(自1970年1月1日起的秒数) |
| iat* | JWT的颁发时间(自1970年1月1日起的秒数) |
| jti* | JWT的唯一标识符,可用于防止JWT被重放 |
| upn* | 一个人类可读的MicroProfile JWT自定义声明,用于唯一标识令牌的主体或用户主体。若该声明缺失,MicroProfile JWT将回退到 preferred_username 声明;若 preferred_username 也缺失,则使用 sub 声明 |
| groups* | MicroProfile JWT自定义声明,列出主体所属的组 |

3. 使用MicroProfile JWT保护交易服务

在对JWT和MicroProfile JWT API有了深入理解后,我们可以使用MicroProfile JWT来保护交易服务。具体步骤如下:
1. 添加扩展 :在编写代码之前,需要添加 quarkus-smallrye-jwt 扩展。

cd transaction_service
mvn quarkus:add-extension -Dextensions="io.quarkus:quarkus-smallrye-jwt"
# 如果交易服务未运行,启动它
mvn clean quarkus:dev -Ddebug=5006
  1. 更新配置文件 :在 application.properties 中更新公钥配置。
# 配置MicroProfile JWT
mp.jwt.verify.publickey=<INSERT PUBLIC KEY HERE>
mp.jwt.verify.issuer=http://keycloak.local/auth/realms/bank
  1. 添加安全REST方法端点 :在 TransactionResource.java 中添加一个方法,用于测试JWT是否允许访问该方法。
@GET
@RolesAllowed("customer")
@Path("/jwt-secure/{acctnumber}/balance")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response jwtGetBalance(
    @PathParam("acctnumber") Long accountNumber) {
    return getBalance(accountNumber);
}
  1. 验证访问 :通过以下命令验证端点的访问。
# 在新终端窗口启动账户服务(如果未运行)
cd account-service
mvn quarkus:dev
# 在章节顶级目录的新窗口中重启交易服务
cd transaction-service
mvn clean quarkus:dev -Ddebug=5006
# 在章节顶级目录的新窗口中获取令牌
TOKEN=`scripts/gettoken.sh`
TRANSACTION_URL=http://localhost:8088
curl -i \
  -H "Accept: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  $TRANSACTION_URL/transactions/jwt-secure/444666/balance

如果访问端点时未提供有效的承载令牌或使用了过期令牌,将收到 HTTP/1.1 401 Unauthorized 消息。

4. 传播JWT

请求可能会跨越多个受保护的微服务,使用JWT可以使安全上下文随请求一起传递,从而实现对这些受保护微服务的访问。接下来,我们将介绍如何将JWT从交易服务传播到账户服务。

4.1 保护账户服务端点

保护账户服务端点的过程与保护交易服务端点类似,具体步骤如下:
1. 添加扩展

cd account_service
mvn quarkus:add-extension -Dextensions="io.quarkus:quarkus-smallrye-jwt"
  1. 更新配置文件
# 配置MicroProfile JWT
mp.jwt.verify.publickey=<INSERT PUBLIC KEY HERE>
mp.jwt.verify.issuer=http://keycloak.local/auth/realms/bank
  1. 添加安全方法 :在 AccountResource.java 中添加一个安全方法,用于获取银行余额。
@RolesAllowed("customer")
@GET
@Path("/jwt-secure/{acctNumber}/balance")
public BigDecimal getBalanceJWT(
    @PathParam("acctNumber") Long accountNumber) {
    return getBalance(accountNumber);
}
4.2 从交易服务传播JWT到账户服务

交易服务使用MicroProfile REST客户端(通过 AccountService.java )访问账户服务。我们需要在 AccountService.java 中添加一个新方法,用于调用账户服务的新安全端点。

@GET
@Path("/jwt-secure/{acctNumber}/balance")
BigDecimal getBalanceSecure(@PathParam("acctNumber") Long accountNumber);

同时,更新 TransactionResource.jwtGetBalance() 方法,以调用新的安全端点。

@GET
@RolesAllowed("customer")
@Path("/jwt-secure/{acctnumber}/balance")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public Response jwtGetBalance(
    @PathParam("acctnumber") Long accountNumber) {
    String balance =
        accountService.getBalanceSecure(accountNumber).toString();
    return Response.ok(balance).build();
}

最后,为了使交易服务能够安全地访问账户服务,需要在交易服务的 application.properties 中更新配置,以传递 Authorization 头部。

org.eclipse.microprofile.rest.client.propagateHeaders=Special-Header,Authorization
5. 在Kubernetes中运行服务

将服务部署到Kubernetes的步骤如下:

cd account-service
eval $(minikube -p minikube docker-env)
mvn clean package -DskipTests -Dquarkus.kubernetes.deploy=true
cd ../transaction-service
mvn clean package -DskipTests -Dquarkus.kubernetes.deploy=true
export TRANSACTION_URL=`minikube service transaction-service --url`
export TOKEN=`../scripts/gettoken.sh`
curl -i \
  -H "Accept: application/json" \
  -H "Authorization: Bearer ${TOKEN}" \
  $TRANSACTION_URL/transactions/jwt-secure/444666/balance

需要注意的是,在Quarkus 2.x中,如果尝试重新部署已经存在于Kubernetes中的应用程序,使用 mvn package -Dquarkus.kubernetes.deploy=true 会导致错误。可以通过先使用 kubectl delete -f /target/kubernetes/minikube.yaml 删除应用程序来解决这个问题。

6. 总结
  • 身份验证和授权是Web应用程序必要的安全策略。
  • Quarkus支持多种身份验证和授权机制。
  • application.properties 中定义用户和授权策略是一种高效的开发方法。
  • Quarkus提供了一些实用功能,可简化对受保护应用程序的测试。
  • OIDC代码授权流程通常使用Web表单获取用户身份并返回JWT。
  • JWT可以使用OIDC隐式流程在服务之间传播用户身份。
  • Quarkus通过WireMock OIDC授权服务器增强了OIDC测试体验。

通过以上步骤,我们可以实现使用JWT和MicroProfile JWT来保护微服务,并在Kubernetes中运行这些服务,从而提高系统的安全性和可扩展性。

graph LR
    A[交易服务] -->|获取令牌| B[Keycloak]
    A -->|携带JWT请求| C[账户服务]
    C -->|验证JWT| D[返回结果]
graph LR
    A[开始] --> B[添加扩展]
    B --> C[更新配置文件]
    C --> D[添加安全方法]
    D --> E[验证访问]
    E --> F[传播JWT]
    F --> G[部署到Kubernetes]
    G --> H[结束]

微服务安全:JWT与MicroProfile JWT的应用

7. 相关技术点索引

以下是一些在微服务安全中涉及的重要技术点及其相关信息:
| 技术点 | 相关描述 |
| ---- | ---- |
| @APIResponse | 用于定义API响应信息 |
| @Asynchronous | 可使方法在单独线程中执行 |
| @Bulkhead | 用于限制并发 |
| @CircuitBreaker | 避免重复失败,有相关参数和异常处理 |
| @ClientHeaderParam | 用于设置客户端请求头参数 |
| @ConfigMapping | 用于配置映射 |
| @ConfigProperties | 用于分组配置属性 |
| @ConfigProperty | 用于获取配置属性 |
| @Fallback | 提供失败时的回退处理 |
| @HeaderParam | 用于获取请求头参数 |
| @Inject | 用于依赖注入 |
| @Liveness | 用于定义存活检查 |
| @Readiness | 用于定义就绪检查 |
| @Retry | 用于从临时失败中恢复 |
| @Timeout | 用于设置执行超时 |
| @Traced | 用于跟踪操作 |

8. 微服务配置相关

配置微服务是确保其正常运行和安全的重要环节,以下是一些关键的配置方面:
- 配置源 :微服务的配置可以来自多种源,如环境变量、配置文件等。
- 分组配置属性 :使用 @ConfigProperties 可以将相关的配置属性进行分组,方便管理。例如:

@ConfigProperties(prefix = "bank")
public class BankConfig {
    private String name;
    private boolean mobileBanking;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isMobileBanking() {
        return mobileBanking;
    }

    public void setMobileBanking(boolean mobileBanking) {
        this.mobileBanking = mobileBanking;
    }
}
  • 配置文件 :在 application.properties 中可以进行各种配置,如公钥验证、颁发者验证等。
# 配置MicroProfile JWT
mp.jwt.verify.publickey=<INSERT PUBLIC KEY HERE>
mp.jwt.verify.issuer=http://keycloak.local/auth/realms/bank
9. 微服务健康检查

微服务的健康检查对于确保系统的稳定性至关重要,以下是一些相关信息:
- MicroProfile Health规范 :定义了微服务的存活和就绪检查机制。
- 存活检查 :用于检查服务是否正在运行。例如,账户服务的存活检查可以通过以下代码实现:

@Liveness
public class AccountHealthReadinessCheck implements HealthCheck {
    @Override
    public HealthCheckResponse call() {
        // 检查逻辑
        if (isAccountServiceAlive()) {
            return HealthCheckResponse.up("Account service is alive");
        } else {
            return HealthCheckResponse.down("Account service is down");
        }
    }

    private boolean isAccountServiceAlive() {
        // 具体检查逻辑
        return true;
    }
}
- **就绪检查**:用于检查服务是否准备好接收请求。
  • Kubernetes探针 :Kubernetes可以使用存活和就绪探针来监控微服务的状态。可以在部署文件中配置探针,例如:
apiVersion: v1
kind: Pod
metadata:
  name: account-service
spec:
  containers:
  - name: account-service
    image: account-service:latest
    ports:
    - containerPort: 8080
    livenessProbe:
      httpGet:
        path: /q/health/live
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20
    readinessProbe:
      httpGet:
        path: /q/health/ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
10. 微服务监控与追踪

微服务的监控和追踪可以帮助我们了解系统的运行状态和性能,以下是一些相关技术:
- MicroProfile Metrics :用于收集微服务的指标,如计数器、计时器等。可以通过注解来定义指标,例如:

import org.eclipse.microprofile.metrics.annotation.Counted;

@Counted(name = "balance_requests", description = "Number of balance requests")
public Response jwtGetBalance(
    @PathParam("acctnumber") Long accountNumber) {
    return getBalance(accountNumber);
}
  • Jaeger :用于分布式追踪,可以帮助我们了解请求在微服务之间的调用路径。安装和配置Jaeger的步骤如下:
    1. 在Minikube环境中设置相关环境变量。
    2. 安装Jaeger Operator。
    3. 配置追踪采样策略。
    4. 在微服务中集成Jaeger客户端。
graph LR
    A[微服务配置] --> B[配置源]
    A --> C[分组配置属性]
    A --> D[配置文件]
    E[微服务健康检查] --> F[MicroProfile Health规范]
    E --> G[Kubernetes探针]
    H[微服务监控与追踪] --> I[MicroProfile Metrics]
    H --> J[Jaeger]
11. 总结与展望

通过使用JWT和MicroProfile JWT,我们可以有效地保护微服务的安全,实现身份验证和授权。同时,结合Kubernetes的部署和管理,以及相关的监控和追踪技术,可以提高系统的稳定性和可维护性。

在未来的微服务开发中,我们可以进一步探索以下方面:
- 优化JWT的使用,如减少令牌大小、提高验证效率等。
- 结合更多的安全机制,如多因素身份验证、加密传输等。
- 深入研究微服务的性能优化和故障处理,以应对更复杂的业务场景。

graph LR
    A[当前实现] --> B[优化JWT使用]
    A --> C[结合更多安全机制]
    A --> D[深入研究性能优化和故障处理]
    B --> E[未来发展]
    C --> E
    D --> E

通过不断地学习和实践,我们可以更好地掌握微服务安全的技术,为构建更安全、高效的系统奠定基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值