我正在使用Java EE Web应用程序,它将利用Keycloak作为身份和身份验证提供程序。此外,出于各种目的,我正在项目中使用Apache DeltaSpike。我想利用DeltaSpike的security module来注释一些方法,这些方法指示用户必须登录才能访问它们。如果此检查失败,我想将用户自动重定向到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的type-aware JSF navigation配置为使用此类进行保护。我用浏览器访问了受保护的资源,并看到触发了我的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?是否有异常或可以引发触发重定向的东西?有什么想法吗?
如果我尝试创建ExceptionHandler并在注入的authenticate()
上调用servletRequest
,则会收到以下异常:
java.lang.IllegalStateException: Attempt to access the request/response without an active HTTP request
org.apache.deltaspike.servlet.impl.produce.RequestResponseHolder.get(RequestResponseHolder.java:105)
org.apache.deltaspike.servlet.impl.produce.ServletObjectProducer.getHttpServletResponse(ServletObjectProducer.java:95)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.apache.webbeans.inject.InjectableMethod.doInjection(InjectableMethod.java:155)
org.apache.webbeans.portable.ProducerMethodProducer.produce(ProducerMethodProducer.java:89)
org.apache.webbeans.portable.AbstractProducer.produce(AbstractProducer.java:134)
org.apache.webbeans.component.AbstractOwbBean.create(AbstractOwbBean.java:122)
org.apache.webbeans.component.ProducerMethodBean.create(ProducerMethodBean.java:95)
org.apache.webbeans.context.creational.BeanInstanceBag.create(BeanInstanceBag.java:76)
org.apache.webbeans.context.AbstractContext.getInstance(AbstractContext.java:159)
org.apache.webbeans.context.AbstractContext.get(AbstractContext.java:125)
org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.getContextualInstance(NormalScopedBeanInterceptorHandler.java:101)
org.apache.webbeans.intercept.RequestScopedBeanInterceptorHandler.getContextualInstance(RequestScopedBeanInterceptorHandler.java:76)
org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.get(NormalScopedBeanInterceptorHandler.java:71)
org.apache.webbeans.custom.servlet.http.HttpServletResponse$$OwbNormalScopeProxy0.isCommitted(javax/servlet/http/HttpServletResponse.java)
org.apache.catalina.connector.Request.authenticate(Request.java:2742)
org.apache.catalina.connector.RequestFacade.authenticate(RequestFacade.java:1081)
org.apache.webbeans.custom.servlet.http.HttpServletRequest$$OwbNormalScopeProxy0.authenticate(javax/servlet/http/HttpServletRequest.java)
[从request
提取response
/ facesContext
对象时,我没有得到此异常:
FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext eCtx = ctx.getExternalContext();
HttpServletResponse response = (HttpServletResponse) eCtx.getResponse();
HttpServletRequest request = (HttpServletRequest) eCtx.getRequest();
request.authenticate(response);
我不太熟悉deltaspike,也没有在测试中添加密钥斗篷。