我正在尝试将自定义参数注释作为参数注入到我的端点。它应该是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 方法似乎根本没有运行,因为我在终端中没有看到日志。
感谢您的意见和帮助, 鲫鱼
我也有类似的问题。我尝试实现自定义
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
注释上的信息,但也许它可以帮助您找到解决方案。