Undertow servlet处理程序丢失已经通过keycloak管理的身份验证和有效的SecurityContext
我试图启用基于角色的访问控制,我已设置使用底池,球衣和CDI的休息终点。我初始化servlet部署如下:Undertow servlet处理程序丢失已经通过keycloak管理的身份验证和有效的SecurityContext
DeploymentInfo servletBuilder = Servlets.deployment()
.setClassLoader(Main.class.getClassLoader())
.setContextPath("/rest")
.setDeploymentName("sv.war")
.addListeners(listener(Listener.class))
.setLoginConfig(new LoginConfig("KEYCLOAK", "some-realm"))
.setAuthorizationManager(auth) // my dummy for testing
.addServlets(servlet("jerseyServlet", ServletContainer.class)
.setLoadOnStartup(1)
.addInitParam("javax.ws.rs.Application", SystemViewApplication.class.getName())
.addMapping("/api/*"));
我启用kecloak认证基于this example code。
所以,我的服务器启动为:
DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder);
manager.deploy();
PathHandler path = Handlers.path(Handlers.resource(staticResources).setDirectoryListingEnabled(false).setWelcomeFiles("index.html"))
.addPrefixPath("/rest", manager.start());
Undertow server = Undertow.builder()
.addHttpListener(8087, "localhost")
.setHandler(sessionHandling(addSecurity(exchange -> {
final SecurityContext context = exchange.getSecurityContext();
if (!context.isAuthenticated()) {
exchange.endExchange();
return;
}
log.info("Authenticated: {} {} {}", context.getMechanismName(), context.getAuthenticatedAccount().getPrincipal().getName(), context.getAuthenticatedAccount().getRoles());
// propagate the request
path.handleRequest(exchange);
})))
.build();
server.start();
如果这两种方法sessionHandling()
和addSecurity()
从例如举起我上面链接。
验证有效,我强制登录,并且Authenticated: ..
记录行用正确的详细信息打印出来。但是,一旦它遇到了servlet处理,安全上下文(和帐户)就会丢失。我跟踪了这个电话,我可以看到在路上的某个时刻,它被替换为全新的SecurityContext
,它有一个空账户。
现在我的问题 - 是否有一些身份验证机制,我错过了将在keycloak身份验证之后传播状态,或者我可以只修复上游代码,并且在SecurityContext
中,如果传入的上下文已经正确验证,该状态并继续前进? (后者看起来不正确,我猜这是因为这可能是servlet部署的不同身份验证?)如果是这样,是否有任何方法连接servlet部署以查看keycloak身份验证已经发生?
柜面有人来就如何servlet的基于keycloak和使用角色的身份验证正确验证这里寻找,这个工作对我来说(注意,这个工作对我来说没有任何XML文件的要求,纯粹与注解。
首先在servlet的应用程序(无论你扩展ResourceConfig
)register()
的RolesAllowedDynamicFeature.class
。
而且在keycloak.json
使"use-resource-role-mappings": true
。
接下来,最初的小号实例化servlet部署ecurity包装:
DeploymentInfo servletBuilder = Servlets.deployment()
.setClassLoader(Main.class.getClassLoader())
.setContextPath("/")
.setDeploymentName("sv.war")
.addListeners(listener(Listener.class))
.setIdentityManager(idm)
.setSessionManagerFactory(new InMemorySessionManagerFactory())
.setInitialSecurityWrapper(handler -> sessionHandling(addSecurity(handler)))
.setResourceManager(staticResources)
.addWelcomePage("index.html")
.addServlets(servlet("jerseyServlet", ServletContainer.class)
.setLoadOnStartup(1)
.addInitParam("javax.ws.rs.Application", SystemViewApplication.class.getName())
.addMapping("/api/*"));
DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder);
manager.deploy();
Undertow server = Undertow.builder()
.addHttpListener(8087, "localhost")
.setHandler(Handlers.path(manager.start()))
.build();
server.start();
哪里sessionHandling(addSecurity(handler))
基本上是从链接GitHub库的代码。
现在认证通过keycloak会工作,也是基于角色的身份验证将正常工作,因此,例如,如果你有一个CDI注入休息终点,如:
@RolesAllowed({"admin", "guest"})
@GET
@Path("/{id}")
public Response findById(@PathParam("id") @NotNull Integer id){
// some method
}
只要角色配置在keyclak中,它应该起作用。