Код: Выделить всё
@Path("/api")
public class MyResource {
@Inject
SecurityIdentity securityIdentity;
@Inject
JsonWebToken jwt;
@GET
@Path("/mydata")
@RolesAllowed("user")
@NoCache
public Uni getMyData(Request request) {
// Get a claim from the Keycloak JWT
String mySpecialClaim = (String) jwt.claim("myCustomClaim").get();
// Do some work...
String resJson = "{result of work here}";
return Uni.createFrom().item(resJson)
.onItem()
.transform(item -> item != "" ? Response.ok(item) : Response.status(Response.Status.NO_CONTENT))
.onItem()
.transform(Response.ResponseBuilder::build);
}
}
< /code>
Токен доступа предоставляется клиентским приложением, которое управляет аутентификацией KeyCloak и который отправляет запрос API с токеном предъявителя. Стандартные вещи, все работают. : -) < /p>
Теперь я хочу сделать что -то похожее с конечной точкой WebSocket. Этот пост в Quarkus github Выпуска:
https://github.com/quarkusio/quarkus/issues/29919
Я кодировал это в соответствии с примером кода в посте. Регистрация показывает, как реагирующие маршрут Отсутствующая часть заключается в том, как кодировать методы OnoPen () и onMessage () в моей конечной точке WebSocket, поэтому они безопасны, реактивны, и я могу получить доступ к JWT, чтобы получить необходимые претензии, которые мне нужны. Я добавил то, что мне нужно, мне нужно в соответствии с образцом ниже.
Код: Выделить всё
@Authenticated
@ServerEndpoint(
value ="/ws",
configurator = WebSocketSecurityConfigurator.class
)
public class WebSocket {
@Inject
UserInfo userInfo;
// ...
}
< /code>
мои дополнения: < /p>
@Authenticated
@ServerEndpoint(
value ="/services/{clientid}",
configurator = WebSocketSecurityConfigurator.class
)
public class WebSocket {
@Inject
SecurityIdentity securityIdentity;
@Inject
JsonWebToken jwt;
@Inject
UserInfo userInfo;
@OnOpen
@RolesAllowed("user") // Is this possible here? Or do I use the JWT and test myself?
public void onOpen(Session session, @PathParam("clientid") String clientid) {
// Get a claim from the Keycloak JWT
String mySpecialClaim = (String) jwt.claim("myCustomClaim").get();
// Do some setup work...
// eg cache the session in a map, etc
}
@OnMessage
public void onMessage(String message, @PathParam("clientid") String clientid) {
// Get a claim from the Keycloak JWT
String myOtherSpecialClaim = (String) jwt.claim("myOtherCustomClaim").get();
// Do some work using the message...
String someMessage = "tell the world";
// Broadcast something ...
myBroadcastFunction(someMessage);
}
}
Код: Выделить всё
@OnOpen
public void onOpen(Session session, @PathParam("clientid") String clientid) {
Log.info("websocket onOpen session=" + session.getId());
}
< /code>
Это бросает: < /p>
Unhandled error in annotated endpoint org.flowt.orgserver.gateway.WebSocketGateway_Subclass@732f20f8
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException:
io.quarkus.runtime.BlockingOperationNotAllowedException: Blocking security check attempted in code running on the event loop.
Make the secured method return an async type, i.e. Uni, Multi or CompletionStage,
or use an authentication mechanism that sets the SecurityIdentity in a blocking manner prior to delegating the call
< /code>
Я хотел бы не блокировать цикл событий, поэтому первое предложение является предпочтительным. < /p>
Но как мне это кодировать? Претензии мне нужны? Я думаю, что я не первый, кто должен сделать это, и должен быть какой -то шаблон для реализации. Документы Quarkus молчат об этом. /> Чтобы разрешить блокирующее исключение, документы Quarkus здесь говорят < /p>
To work around this you need to @Inject an instance
of io.quarkus.security.identity.CurrentIdentityAssociation,
and call the Uni getDeferredIdentity(); method.
You can then subscribe to the resulting Uni and will be
notified when authentication is complete and the identity
is available.
< /code>
Я не могу понять, как реализовать эту инструкцию. Отладка в коде Quarkus Я вижу, что мой access_token обрабатывается, пользователь извлекается из KeyCloak, но отложенная идентичность не устанавливается. Поэтому OnoPen () import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.websocket.Session;
import javax.websocket.OnOpen;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import io.quarkus.logging.Log;
import io.quarkus.security.Authenticated;
import io.quarkus.security.identity.CurrentIdentityAssociation;
import io.quarkus.security.identity.SecurityIdentity;
import io.smallrye.mutiny.Uni;
@ApplicationScoped
@Authenticated
@ServerEndpoint(value = "/services/{clientid}", configurator = WebSocketSecurityConfigurator.class)
public class WebSocketGateway {
@Inject
SecurityIdentity securityIdentity;
@Inject
CurrentIdentityAssociation identities;
@OnOpen
public Uni onOpen(Session session, @PathParam("clientid") String clientid) {
// This never runs
Log.info("=========================== onOpen session=" + session.getId());
return identities.getDeferredIdentity()
.onItem()
.transformToUni(identity -> {
// Just to see if we reach here
Log.info("identity=" + identity.toString());
return Uni.createFrom().voidItem();
});
}
}
< /code>
и просто для повторного завершения: конечные точки REST в этом же приложении для той же зарегистрированной работы пользователя отлично работают. < /p>
Спасибо,
murray < /p>
Подробнее здесь: https://stackoverflow.com/questions/751 ... cloak-oidc
Мобильная версия