使用ParamConverterProvider自定义参数注入无法正常工作

问题描述 投票:0回答:1

我正在尝试将自定义参数注释作为参数注入到我的端点。它应该是keycloak中的一个角色,看起来像这样:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface KeycloakRole {
    String realm();
    String role();
}

我有一个转换器类:

public class KeycloakRoleConverter implements ParamConverter<Set<String>> {
    private final Set<String> userRoles;
    public KeycloakRoleConverter(Set<String> userRoles) {
        this.userRoles = userRoles;
    }

    @Override
    public Set<String> fromString(String value) {
        if (!userRoles.contains(value)) {
            throw new WebApplicationException("User does not have required role");
        }
        return Set.of(value);
    }

    @Override
    public String toString(Set<String> value) {
        return value.iterator().next();
    }
}

带有转换器提供者类:

@RequestScoped
@Provider
@Priority(Priorities.USER)
public class KeycloakRoleResolver implements ParamConverterProvider {

    @Context
    SecurityContext securityContext;

    @Override
    public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
        LOG.infof("getConverter has been called");
        for (Annotation annotation : annotations) {
            if (annotation.annotationType() == KeycloakRole.class) {
                KeycloakRole keycloakRole = (KeycloakRole) annotation;
                Set<String> userRoles = getUserRoles(keycloakRole.realm());
                return (ParamConverter<T>) new KeycloakRoleConverter(userRoles);
            }
        }
        return null;
    }

    private Set<String> getUserRoles(String realm) {
        KeycloakSecurityContext keycloakSecurityContext = (KeycloakSecurityContext) securityContext;
        AccessToken token = keycloakSecurityContext.getToken();
        if (token == null) {
            throw new WebApplicationException("Unable to obtain user roles");
        }

        Map<String, Object> otherClaims = token.getOtherClaims();
        JsonArray resourceAccessArray = (JsonArray) otherClaims.get("resource_access");
        JsonObject resourceAccess = resourceAccessArray.getJsonObject(0);
        JsonObject profilerCore = resourceAccess.getJsonObject("profiler-core");
        JsonArray rolesArray = profilerCore.getJsonArray("roles");

        Set<String> userRoles = new HashSet<>();
        for (int i = 0; i < rolesArray.size(); i++) {
            userRoles.add(rolesArray.getString(i));
        }

        return userRoles;
    }

我的终点:

@Path("/api/profile")
@Authenticated
@ApplicationScoped
public class AdminResource {

    @GET
    @Path("/custom-role-ep")
    @Consumes(MediaType.APPLICATION_JSON)
    public Collection<String> customEp(@KeycloakRole(realm = "profiler", role = "view-all") Set<String> userRoles) {
        LOG.info("User roles: " + userRoles);
        return userRoles;
    }
}

我正在使用带有 keycloak 访问令牌的邮递员,并希望输出用户的角色。

我在 quarkus 应用程序中使用它。由于某种原因,userRoles 输出始终为空。奇怪的是我的 getConverter 方法似乎根本没有运行,因为我在终端中没有看到日志。

感谢您的意见和帮助, 鲫鱼

java keycloak quarkus
1个回答
0
投票

我也有类似的问题。我尝试实现自定义

ContainerRequestFilter
或自定义
ParamConverterProvider
,但我总是将
null
对象传递到我的控制器。就我而言,我想用它来分页。以下是我如何使用
@BeanParam
注释在 quarkus 中解决这个问题(在本例中我使用 kotlin,但它应该会给你带来好处。):

class PaginationParams {

    @QueryParam("page")
    var page: Int? = null

    @QueryParam("size")
    var size: Int? = null

    fun toPage(): Page {
        val pageIndex = this.page ?: 0
        val pageSize = this.size ?: Int.MAX_VALUE
        return Page.of(pageIndex, pageSize)
    }
}

然后在你的控制器中,只需使用:

@GET
fun getMyResource(@BeanParam page: PaginationParams): Paged<MyResource> =
        myService.getMyResource(page)

在这种情况下,我无法告诉您如何使用自定义

@KeycloakRole
注释上的信息,但也许它可以帮助您找到解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.