使用 OpenID Connect(OIDC)Bearer 令牌认证保护服务应用

使用 OpenID Connect(OIDC)Bearer 令牌认证保护服务应用

使用Quarkus OpenID Connect(OIDC)扩展,通过Bearer令牌认证保护Jakarta REST应用。Bearer令牌由兼容OIDC与OAuth 2.0的授权服务器签发,例如Keycloak。

有关OIDC Bearer令牌认证的更多信息,参见Quarkus OpenID Connect(OIDC)Bearer token authentication指南。

如需使用OIDC授权码流程保护Web应用,参见使用 OpenID Connect 授权码流程保护 Web 应用指南。

前置条件

完成本指南需要:

  • 约15分钟。

  • 一个IDE。

  • 安装JDK 17或更高版本,并正确配置JAVA_HOME。

  • Apache Maven 3.9.16。

  • 可用的容器运行时,Docker或Podman。

  • 可选:如果希望通过Quarkus CLI操作,安装该工具。

  • 可选:如需构建原生可执行文件,安装并正确配置Mandrel或GraalVM;使用容器构建原生文件时也可使用Docker。

  • jq命令行处理工具。

架构

本示例构建一个简单微服务,提供两个端点:

  • /api/users/me

  • /api/admin

这些端点受保护。客户端必须随请求发送Bearer令牌,令牌需要有效(例如签名、有效期和受众均符合要求),并受到微服务信任,才能访问。

Keycloak服务器签发Bearer令牌,令牌代表其签发对象。由于Keycloak是OAuth 2.0授权服务器,令牌还会标识代表用户操作的客户端。

任何持有有效令牌的用户都能访问/api/users/me。该端点根据令牌信息返回包含用户详情的JSON文档。

/api/admin通过RBAC(基于角色的访问控制)保护,仅admin角色可访问;端点使用@RolesAllowed声明式地实施访问约束。

完整方案

可以按后续步骤逐步创建应用,也可以直接查看完成的示例。

运行git clone https://github.com/quarkusio/quarkus-quickstarts.git克隆仓库,或者下载归档文件。

完整方案位于security-openid-connect-quickstart目录。

创建 Maven 项目

可以新建包含oidc扩展的Maven项目,也可以把扩展加入现有项目。选择以下适用的命令。

新建Maven项目:

CLI

quarkus create app org.acme:security-openid-connect-quickstart \
    --extension='oidc,rest-jackson' \
    --no-code
cd security-openid-connect-quickstart

如需Gradle项目,添加--gradle或--gradle-kotlin-dsl选项。

Quarkus CLI的安装与用法参见Quarkus CLI指南。

Maven

mvn io.quarkus.platform:quarkus-maven-plugin:3.40.1:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=security-openid-connect-quickstart \
    -Dextensions='oidc,rest-jackson' \
    -DnoCode
cd security-openid-connect-quickstart

如需Gradle项目,添加-DbuildTool=gradle或-DbuildTool=gradle-kotlin-dsl选项。

Windows用户请注意:

  • 使用cmd时,不要使用反斜杠\续行,应把整个命令放在同一行。

  • 使用PowerShell时,用双引号包裹-D参数,例如"-DprojectArtifactId=security-openid-connect-quickstart"。

现有Quarkus项目可以在项目根目录运行以下命令,添加oidc扩展:

CLI

quarkus extension add oidc

Maven

./mvnw quarkus:add-extension -Dextensions='oidc'

Gradle

./gradlew addExtension --extensions='oidc'

这会在构建文件中加入以下依赖:

pom.xml

<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-oidc</artifactId>
</dependency>

build.gradle

implementation("io.quarkus:quarkus-oidc")

编写应用

  1. 按下面的普通Jakarta REST资源示例,实现/api/users/me:

    package org.acme.security.openid.connect;
    
    import jakarta.annotation.security.RolesAllowed;
    import jakarta.inject.Inject;
    import jakarta.ws.rs.GET;
    import jakarta.ws.rs.Path;
    
    import org.jboss.resteasy.reactive.NoCache;
    import io.quarkus.security.identity.SecurityIdentity;
    
    @Path("/api/users")
    public class UsersResource {
    
        @Inject
        SecurityIdentity securityIdentity;
    
        @GET
        @Path("/me")
        @RolesAllowed("user")
        @NoCache
        public User me() {
            return new User(securityIdentity);
        }
    
        public static class User {
    
            private final String userName;
    
            User(SecurityIdentity securityIdentity) {
                this.userName = securityIdentity.getPrincipal().getName();
            }
    
            public String getUserName() {
                return userName;
            }
        }
    }
  2. 按以下示例实现/api/admin:

    package org.acme.security.openid.connect;
    
    import jakarta.annotation.security.RolesAllowed;
    import jakarta.ws.rs.GET;
    import jakarta.ws.rs.Path;
    import jakarta.ws.rs.Produces;
    import jakarta.ws.rs.core.MediaType;
    
    @Path("/api/admin")
    public class AdminResource {
    
        @GET
        @RolesAllowed("admin")
        @Produces(MediaType.TEXT_PLAIN)
        public String admin() {
            return "granted";
        }
    }

    主要区别是使用@RolesAllowed验证调用者是否被授予admin角色,仅该角色可以访问端点。

SecurityIdentity既可在@RequestScoped中注入,也可在@ApplicationScoped中注入。

配置应用

  • 在src/main/resources/application.properties中设置以下属性,配置Quarkus OIDC扩展。

    %prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
    quarkus.oidc.client-id=backend-service
    quarkus.oidc.credentials.secret=secret
    
    # Tell Dev Services for Keycloak to import the realm file
    # This property is not effective when running the application in JVM or native modes
    
    quarkus.keycloak.devservices.realm-path=quarkus-realm.json

其中:

  • %prod.quarkus.oidc.auth-server-url指定OIDC服务器基础URL。%prod.配置档前缀保证在开发模式下由Dev Services for Keycloak启动容器。详情见“以开发模式运行应用”。

  • quarkus.oidc.client-id设置用于标识应用的客户端ID。

  • quarkus.oidc.credentials.secret设置客户端密钥,供client_secret_basic认证方法使用。

更多配置参见OpenID Connect(OIDC)configuration properties指南。

以开发模式运行应用

把realm配置文件放入src/main/resources目录,使它被复制到类路径并自动导入Keycloak。如果已构建完整示例,则构建时会把该realm文件加入类路径,无需重复此步骤。

  1. 使用以下命令启动开发模式:

    CLI

    quarkus dev

    Maven

    ./mvnw quarkus:dev

    Gradle

    ./gradlew --console=plain quarkusDev
  2. 打开/q/dev-ui中的Dev UI,在OpenID Connect卡片中点击Keycloak provider链接。

  3. 当OpenID Connect Dev UI提供的单页应用要求登录时,执行以下步骤:

    • 以alice登录,密码为alice;该用户具有user角色。

      • 访问/api/admin返回403。

      • 访问/api/users/me返回200。

    • 退出后,以admin登录,密码为admin;该用户同时具有admin和user角色。

      • 访问/api/admin返回200。

      • 访问/api/users/me返回200。

启动并配置 Keycloak 服务器

在开发模式运行应用时,不要另行启动Keycloak服务器;Dev Services for Keycloak会启动并配置容器。详情见前文开发模式章节。

要自行启动Keycloak服务器,可以使用以下Docker命令:

docker run --name keycloak -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:26.7.4 start-dev
  1. Keycloak服务器可通过localhost:8180访问。

  2. 使用以下示例凭据以admin用户登录Keycloak管理控制台:

    • 用户名:admin。

    • 密码:admin。

  3. 从上游社区仓库导入realm配置文件,创建新的realm。

更多信息参见Keycloak文档中创建和配置realm的说明。

如果要通过应用中的Keycloak Admin Client配置服务器,根据所用技术栈选择扩展:

  • Quarkus REST:使用quarkus-rest、quarkus-rest-client或两者时,加入quarkus-keycloak-admin-rest-client。

  • RESTEasy Classic:使用quarkus-resteasy、quarkus-resteasy-client或两者时,加入quarkus-keycloak-admin-resteasy-client。

  • 未明确使用REST层时,建议加入quarkus-keycloak-admin-rest-client。

这些规则使Keycloak Admin Client能够与所用REST框架配合,不论使用REST服务器、REST客户端还是二者。

更多信息参见Quarkus Keycloak 管理客户端指南。

以 JVM 模式运行应用

  1. 编译应用:

    CLI

    quarkus build

    Maven

    ./mvnw install

    Gradle

    ./gradlew build
  2. 运行应用:

    java -jar target/quarkus-app/quarkus-run.jar

以原生模式运行应用

同一示例无需修改即可编译为原生可执行文件。这样生产环境中不再需要安装JVM;所需运行时包含在二进制文件中,并经过优化以降低资源需求。

原生编译耗时更长,因此默认不启用。

  1. 启用native配置重新构建:

    CLI

    quarkus build --native

    Maven

    ./mvnw install -Dnative

    Gradle

    ./gradlew build -Dquarkus.native.enabled=true
  2. 等待构建完成后,可直接运行以下二进制文件:

    ./target/security-openid-connect-quickstart-1.0.0-SNAPSHOT-runner

测试应用

开发模式的测试方法参见前面的开发模式章节。

JVM或原生模式启动的应用,可以使用curl测试。

  • 应用采用Bearer令牌认证,因此访问资源前,必须先从Keycloak获取访问令牌:

export access_token=$(\
    curl --insecure -X POST http://localhost:8180/realms/quarkus/protocol/openid-connect/token \
    --user backend-service:secret \
    -H 'content-type: application/x-www-form-urlencoded' \
    -d 'username=alice&password=alice&grant_type=password' | jq --raw-output '.access_token' \
 )

当quarkus.oidc.authentication.user-info-required设为true,要求使用访问令牌请求UserInfo时,令牌授权请求还必须添加scope=openid参数,例如:

export access_token=$(\
    curl --insecure -X POST http://localhost:8180/realms/quarkus/protocol/openid-connect/token \
    --user backend-service:secret \
    -H 'content-type: application/x-www-form-urlencoded' \
    -d 'username=alice&password=alice&grant_type=password&scope=openid' | jq --raw-output '.access_token' \
 )

上例获取的是alice用户的访问令牌。

  • 持有有效令牌的任意用户都可访问http://localhost:8080/api/users/me,获取包含用户详情的JSON负载。

curl -v -X GET \
  http://localhost:8080/api/users/me \
  -H "Authorization: Bearer "$access_token
  • 只有admin角色可以访问http://localhost:8080/api/admin。使用此前为alice签发的令牌访问,会得到403响应。

curl -v -X GET \
   http://localhost:8080/api/admin \
   -H "Authorization: Bearer "$access_token
  • 如需访问管理员端点,先获取admin用户的令牌:

export access_token=$(\
    curl --insecure -X POST http://localhost:8180/realms/quarkus/protocol/openid-connect/token \
    --user backend-service:secret \
    -H 'content-type: application/x-www-form-urlencoded' \
    -d 'username=admin&password=admin&grant_type=password' | jq --raw-output '.access_token' \
 )

关于依赖Dev Services for Keycloak的集成测试,参见OIDC Bearer令牌认证指南中的Dev Services for Keycloak章节。

参考资料

正文相关链接

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容