切换Pac4j+Shiro+Keycloak后JSF Ajax请求失效问题排查
问题分析与解决方案
这不是Pac4j或Shiro的Bug,而是默认授权配置与JSF Ajax请求的适配问题,以下是具体原因和正确配置方案:
原因解析
Pac4j的SecurityFilter默认启用了两个授权器:
CsrfAuthorizer:检查请求是否携带名为pac4jCsrfToken的参数或请求头,用于防范CSRF攻击IsAuthenticatedAuthorizer:验证用户是否已完成认证
而JSF(尤其是PrimeFaces)的Ajax请求使用自身的CSRF机制(比如JSF 2.2+的javax.faces.Token或PrimeFaces内置CSRF token),不会自动携带Pac4j要求的pac4jCsrfToken,因此触发CsrfAuthorizer校验失败,请求被拦截后无法触发后台Bean的方法。
正确配置方案(替代authorizers = none)
方案1:让Pac4j识别JSF的CSRF Token
修改shiro.ini中oidcSecurityFilter的授权器配置,将CsrfAuthorizer的参数名改为JSF使用的CSRF参数名。
- 针对JSF 2.2+的
javax.faces.Token:
oidcSecurityFilter.authorizers = csrfAuthorizer, isAuthenticatedAuthorizer # 配置适配JSF的CSRF授权器 csrfAuthorizer = org.pac4j.core.authorization.authorizer.CsrfAuthorizer csrfAuthorizer.parameterName = javax.faces.Token
- 针对PrimeFaces的
csrfToken:
csrfAuthorizer.parameterName = csrfToken
方案2:在JSF页面中添加Pac4j的CSRF Token
在包含Ajax请求的<h:form>内添加隐藏字段,携带Pac4j的CSRF Token,让Ajax请求自动带上该参数:
<h:form> <h:inputHidden name="pac4jCsrfToken" value="#{pac4jCsrfToken}" /> <p:ajax event="load" listener="#{myBean.init()}" /> <!-- 其他表单组件 --> </h:form>
方案3:针对Ajax请求跳过CSRF校验(谨慎使用)
若不需要对JSF Ajax请求做Pac4j的CSRF校验,可自定义授权逻辑或配置CsrfAuthorizer仅针对非Ajax请求检查,但这种方式会降低安全性,建议优先使用前两种方案。
内容的提问来源于stack exchange,提问作者vished2000
相关产品推荐
相关产品推荐

