Mur*_*rah 6 java websocket openid-connect keycloak quarkus
我已经陷入了很多兔子洞,但无法使其正常工作。我希望有人能帮助我。
我正在使用 Keycloak,并且我的 REST 端点已成功保护,如以下简短示例所示:
@Path("/api")
public class MyResource {
@Inject
SecurityIdentity securityIdentity;
@Inject
JsonWebToken jwt;
@GET
@Path("/mydata")
@RolesAllowed("user")
@NoCache
public Uni<Response> 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);
}
}
Run Code Online (Sandbox Code Playgroud)
访问令牌由客户端应用程序提供,该应用程序管理 Keycloak 身份验证并使用不记名令牌发送 API 请求。标准的东西,一切正常。:-)
现在,我想对 WebSocket 端点执行类似的操作。
我使用Quarkus Websockets示例作为我的指南,无需授权即可使其全部工作 - 即进行不安全的调用。
我在尝试保护 WebSocket 连接时陷入困境。
我最接近找到解决方案的是 Quarkus GitHub 问题中的这篇文章: https: //github.com/quarkusio/quarkus/issues/29919
我已经按照帖子中的示例代码对其进行了编码。日志记录显示reactive route和WebSocketSecurityConfigurator都被调用,并且access_token来自 JS WebSocket 客户端的 存在并且可能正在由 Quarkus 默认安全进程处理,就像 REST 端点一样。都好。
缺少的部分是如何在我的 WebSocket 端点中编码onOpen()和onMessage()方法,以便它们是安全的、反应性的,并且我可以访问 JWT 来获取我需要的声明。
任何人都可以详细说明上面提到的 Quarkus 问题帖子中的这段代码片段吗?我已经根据下面的示例添加了我认为我需要的内容。
问题帖子的片段:
@Authenticated
@ServerEndpoint(
value ="/ws",
configurator = WebSocketSecurityConfigurator.class
)
public class WebSocket {
@Inject
UserInfo userInfo;
// ...
}
Run Code Online (Sandbox Code Playgroud)
我的补充:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
在非安全版本中,onOpen()和onMessage()方法会返回void,因为当然,与 REST 端点不同,它会广播结果而不是返回结果。
在这个安全版本中,这是行不通的。如果我只有一个 onOpen() 方法,并按如下方式编码:
@OnOpen
public void onOpen(Session session, @PathParam("clientid") String clientid) {
Log.info("websocket onOpen session=" + session.getId());
}
Run Code Online (Sandbox Code Playgroud)
它抛出:
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
Run Code Online (Sandbox Code Playgroud)
我不想阻止事件循环,因此第一个建议是首选。
但我应该如何编码呢?
@RolesAllowed("user")在这种情况下仍然有效吗?我不会在这里浪费空间与我所有失败的尝试。我想我不是第一个需要这样做的人,并且必须有某种模式来实施。Quarkus 文档对此保持沉默。
谁能告诉我如何使用 Quarkus 编写onOpen()和onMessage()方法,以便 WebSocket 端点得到保护并且 JWT 在这些方法中可用?
编辑=======
为了解决阻塞异常,Quarkus 文档在这里说
To work around this you need to @Inject an instance
of io.quarkus.security.identity.CurrentIdentityAssociation,
and call the Uni<SecurityIdentity> getDeferredIdentity(); method.
You can then subscribe to the resulting Uni and will be
notified when authentication is complete and the identity
is available.
Run Code Online (Sandbox Code Playgroud)
我不知道如何执行该指令。调试 Quarkus 代码,我看到我的 access_token 正在处理,从 Keycloak 检索用户,但未设置 deferredIdentity。因此onOpen()永远不会运行。
显然这不是文档想要我做的!
这是我的课程:
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
Run Code Online (Sandbox Code Playgroud)
重申一下:同一应用程序中同一登录用户的 REST 端点可以完美工作。
谢谢,穆雷
| 归档时间: |
|
| 查看次数: |
1236 次 |
| 最近记录: |