如何在Keycloak和Apache Deltaspike中重定向到登录页面?

影人

我正在开发一个Java EE Web应用程序,它将利用Keycloak作为身份和身份验证提供程序。此外,出于各种目的,我正在项目中使用Apache DeltaSpike我想利用DeltaSpike的安全模块来注释方法,指示用户必须登录才能访问它们。如果此检查失败,我想将用户自动重定向到Keycloak登录页面。但是,我还没有找到一种方法来实现这一目标。

相关的y web.xml文件如下所示,表明我已将Keycloak配置为我的应用程序的安全性机制:

<login-config>
    <auth-method>KEYCLOAK</auth-method>
    <realm-name>KEYCLOAK</realm-name>
</login-config>

我已经实现了一个AccessDecisionVoter类似如下的代码:

public class LoginRequiredAccessDecisionVoter extends AbstractAccessDecisionVoter {

    @Inject
    private KeycloakSecurityContext securityContext = null;

    /*
     * (non-Javadoc)
     *
     * @see
     * org.apache.deltaspike.security.api.authorization.AbstractAccessDecisionVoter#
     * checkPermission(org.apache.deltaspike.security.api.authorization.
     * AccessDecisionVoterContext, java.util.Set)
     */
    @Override
    protected void checkPermission(AccessDecisionVoterContext accessDecisionVoterContext,
            Set<SecurityViolation> violations) {
        if (securityContext == null) {
            violations.add(new LoginRequiredSecurityViolation());
        }
    }

}

然后,我将DeltaSpike的类型感知JSF导航配置为使用此类保护。我用浏览器访问了受保护的资源,发现我AccessDecisionVoter被触发了。我看到该checkPermission方法被调用ErrorViewAwareAccessDeniedException并被抛出。因此,我实现了一个ExceptionHandler捕获异常并将用户重定向到Keycloak登录页面。看起来像这样:

@ExceptionHandler
public class SecurityExceptionHandler {

    @Inject
    private HttpServletRequest servletRequest = null;

    @Inject
    @DeltaSpike
    private HttpServletResponse servletResponse = null;

    /**
     * Handles {@link ErrorViewAwareAccessDeniedException} exceptions
     * 
     * @param event The exception event
     */
    public void handleErrorViewAwareAccessDeniedException(
            @Handles ExceptionEvent<ErrorViewAwareAccessDeniedException> event) {
        Set<SecurityViolation> violations = event.getException().getViolations();
        for (SecurityViolation v : violations) {
            if (v instanceof LoginRequiredSecurityViolation) {
                try {
                    this.servletRequest.authenticate(this.servletResponse);
                    event.handled();
                } catch (IOException | ServletException e) {
                }
            }
        }
    }
}

我的想法是该servletRequest.authenticate()呼叫将启动重定向到Keycloak登录页面的重定向。但是,事实并非如此。相反,我得到一个ServletException/NullPointerException抛出。

是否有更好的方法以编程方式将用户重定向到Keycloak?是否有异常或可以引发触发重定向的东西?有什么想法吗?

更新:这是我收到的异常:

11:17:54,256 ERROR [io.undertow.request] (default task-1) UT005023: Exception handling request to /tests/loginTest.xhtml: javax.servlet.ServletException
    at javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:725)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:451)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
    at org.apache.deltaspike.servlet.impl.event.EventBridgeFilter.doFilter(EventBridgeFilter.java:59)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at org.apache.deltaspike.servlet.impl.produce.RequestResponseHolderFilter.doFilter(RequestResponseHolderFilter.java:63)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:55)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.lambda$handleRequest$1(ElytronRunAsHandler.java:68)
    at org.wildfly.security.auth.server.FlexibleIdentityAssociation.runAsFunctionEx(FlexibleIdentityAssociation.java:103)
    at org.wildfly.security.auth.server.Scoped.runAsFunctionEx(Scoped.java:161)
    at org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:73)
    at org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.handleRequest(ElytronRunAsHandler.java:67)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:53)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:59)
    at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at org.wildfly.elytron.web.undertow.server.servlet.CleanUpHandler.handleRequest(CleanUpHandler.java:38)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
    at org.keycloak.adapters.elytron.KeycloakServletExtension.lambda$null$0(KeycloakServletExtension.java:39)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
    at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
    at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:364)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
    at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1982)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
    at io.undertow.servlet.spec.HttpServletRequestImpl.getRequestDispatcher(HttpServletRequestImpl.java:957)
    at com.sun.faces.context.ExternalContextImpl.dispatch(ExternalContextImpl.java:692)
    at javax.faces.context.ExternalContextWrapper.dispatch(ExternalContextWrapper.java:91)
    at com.sun.faces.application.view.JspViewHandlingStrategy.executePageToBuildView(JspViewHandlingStrategy.java:356)
    at com.sun.faces.application.view.JspViewHandlingStrategy.buildView(JspViewHandlingStrategy.java:106)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:78)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:76)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:199)
    at org.apache.deltaspike.jsf.impl.listener.request.DeltaSpikeLifecycleWrapper.render(DeltaSpikeLifecycleWrapper.java:111)
    at javax.faces.lifecycle.LifecycleWrapper.render(LifecycleWrapper.java:88)
    at org.apache.deltaspike.jsf.impl.listener.request.JsfClientWindowAwareLifecycleWrapper.render(JsfClientWindowAwareLifecycleWrapper.java:160)
    at javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:708)
    ... 57 more
影人

解决了!它所需要的只是在通话FacesContext#responseComplete()之前authenticate打电话。因此,代码的相关部分现在看起来像这样(也做了一些清理):

FacesContext ctx = FacesContext.getCurrentInstance();
HttpServletRequest req = (HttpServletRequest) ctx.getExternalContext().getRequest();
HttpServletResponse resp = (HttpServletResponse) ctx.getExternalContext().getResponse();

ctx.responseComplete();
req.authenticate(resp);

event.handled();

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

在ReactJS中成功登录后如何重定向到页面?

如何重定向到 ABP 中的登录页面?

在liferay中,如何重定向到登录页面并返回?

登录和签出用户重定向到主页如何在SAP Hybris中重定向到购物车页面

如何重定向到登录页面?

如果用户未登录,如何重定向到登录页面?

如何重定向到登录页面并在该页面中显示消息

如何在Angular 5中的401响应上重定向到登录页面?

如何从php中的登录页面重定向到“上一页和仪表板”

在jsf2.2和primefaces中登录后重定向到默认(主页)页面

如何重定向到Django中的页面

如何将用户从 django rest 框架中的中间件重定向到登录页面?

使用Spring Security Core插件在Grails中登录后如何重定向到页面

如果会话在MVC中不可用,如何重定向到登录页面

如何使用 lua 代码重定向到 EnvoyFilter 中的登录页面?

当会话在Java Web应用程序中过期时,如何重定向到登录页面?

如果使用angular中的模块,如果路径为空,如何重定向到登录页面

在angularjs中成功登录后如何重定向到其他页面?

如何将用户重定向到MVC中的登录页面

如何重定向到登录页面并再次返回到Wordpress中的请求链接

如何从ASP NET Core中的AuthorizationFilter重定向到登录页面?

Spring Security和Angular javascript重定向到登录页面

如何使用React正确重定向到登录页面

登录后如何重定向到自定义页面?

如果principal为null,如何重定向到登录页面

如何重定向到ASP.NET Ideneity登录页面?

使用IdentityServices注销后如何重定向到“登录”页面

登录后如何重定向到其他页面

如何强制联合注销重定向到登录页面?