1.6. 步骤验证
io.quarkus.oidc.AuthenticationContext 注解可用于列出一个或多个身份验证上下文参考(ACR)值,以便为 Jakarta REST 资源类和方法强制实施所需的身份验证级别。当令牌没有预期的身份验证上下文参考(ACR)值时,OAuth 2.0 步骤验证挑战协议 引入了一种资源服务器的机制,以请求更强大的身份验证方法。考虑以下示例:
package io.quarkus.it.oidc;
import io.quarkus.oidc.AuthenticationContext;
import io.quarkus.oidc.BearerTokenAuthentication;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@BearerTokenAuthentication
@Path("/")
public class GreetingsResource {
@Path("hello")
@AuthenticationContext("myACR")
@GET
public String hello() {
return "hello";
}
@Path("hi")
@AuthenticationContext(value = "myACR", maxAge = "PT120m")
@GET
public String hi() {
return "hi";
}
}
quarkus.http.auth.proactive=false
- 1
- 禁用主动身份验证,以便在 Quarkus 验证传入请求前与端点匹配
@AuthenticationContext注释。
如果 bearer 访问令牌声明 acr 不包含 myACR,Quarkus 会返回一个身份验证要求质询,表示所需的 acr_values :
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="insufficient_user_authentication",
error_description="A different authentication level is required",
acr_values="myACR"
当单页应用程序(SPA)等客户端收到 不足_user_authentication 错误代码的挑战时,必须解析 acr_values,请求一个必须满足 acr_values 约束的新用户登录,并使用新的访问令牌访问 Quarkus。
io.quarkus.oidc.AuthenticationContext 注解还可用于为 WebSockets Next 服务器端点强制实施所需的身份验证级别。该注解必须放在端点类上,因为在 HTTP 连接升级到 WebSocket 连接之前创建 SecurityIdentity。有关 HTTP 升级安全性的更多信息,请参阅 Quarkus "WebSockets Next reference" 指南中的 Secure HTTP 升级 部分。
也可以为 OIDC 租户强制实施所需的身份验证级别:
quarkus.oidc.hr.token.required-claims.acr=myACR
或者,如果您需要更大的灵活性,请编写 Jose4j Validator :
package io.quarkus.it.oidc;
import java.util.Map;
import jakarta.enterprise.context.ApplicationScoped;
import org.jose4j.jwt.MalformedClaimException;
import org.jose4j.jwt.consumer.JwtContext;
import org.jose4j.jwt.consumer.Validator;
import io.quarkus.arc.Unremovable;
import io.quarkus.oidc.TenantFeature;
import io.quarkus.oidc.common.runtime.OidcConstants;
import io.quarkus.security.AuthenticationFailedException;
@Unremovable
@ApplicationScoped
@TenantFeature("hr")
public class AcrValueValidator implements Validator {
@Override
public String validate(JwtContext jwtContext) throws MalformedClaimException {
var jwtClaims = jwtContext.getJwtClaims();
if (jwtClaims.hasClaim("acr")) {
var acrClaim = jwtClaims.getStringListClaimValue("acr");
if (acrClaim.contains("myACR") && acrClaim.contains("yourACR")) {
return null;
}
}
String requiredAcrValues = "myACR,yourACR";
throw new AuthenticationFailedException(Map.of(OidcConstants.ACR_VALUES, requiredAcrValues));
}
}