使用事务包装 Spring Security 自定义身份验证提供程序
Posted
技术标签:
【中文标题】使用事务包装 Spring Security 自定义身份验证提供程序【英文标题】:Wrapping Spring Security custom authentication provider with transaction 【发布时间】:2011-06-21 11:14:32 【问题描述】:在我的自定义身份验证提供程序中,我能够通过我的服务 API 获取域对象,但是当我从一个域对象爬到另一个域对象以获取特定值以执行额外检查时,Spring 抱怨 Hibernate 会话不存在:-
domain.getAnotherDomain().getProperty(); // epic FAIL
我有以下 AOP 事务来用事务包装我的所有项目 API,我很确定我的自定义身份验证提供程序属于以下模式:-
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor pointcut="execution(* my.project..*.*(..))" advice-ref="txAdvice" />
</aop:config>
我也配置了 OpenSessionInView 过滤器,但我认为这无论如何都不适用于 Spring Security。
我想我可以创建一个特定的服务 API 来执行所有必需的检查,但我很好奇为什么我不能用适当的事务来包装我的自定义身份验证提供程序。
有什么解释吗?谢谢。
【问题讨论】:
【参考方案1】:我的解决方案是创建一个服务 API 来执行检查,以避免在我的自定义身份验证提供程序中出现延迟加载错误。
【讨论】:
【参考方案2】:Spring 抱怨 Hibernate 会话不存在
不太确定我是否理解了您的所有问题,但我认为上述陈述代表了您的主要问题,对吧?您没有提供任何堆栈跟踪,但我想这是臭名昭著的“没有会话或会话关闭”,这是您刚才描述的典型场景:
domain.getAnotherDomain().getProperty(); // 史诗般的失败
也许我遗漏了一些东西,但我认为典型的答案也适用于这里:映射您与 fetch=FetchType.EAGER
的关系,这样您就不必在会话已经关闭时延迟加载它。
【讨论】:
异常消息是failed to lazily initialize a collection of role: ss.domain, no session or session was closed
。除非绝对必要,否则我不喜欢执行 Eager fetching ......也就是说,如果我让事务包装自定义身份验证提供程序类。
好吧,如果您在一个会话中加载了domain
,您将无法在另一个会话中从domain
懒惰地加载anotherDomain
。不过,我不确定这会是你的情况(我从你的问题中不清楚)。但是你可以考虑使用 Fetch Profiles,如果你不想总是进行 Eager 加载,但你知道有时你需要。【参考方案3】:
您尚未发布任何可以让我们提出任何有意义建议的代码。
但是自定义身份验证提供程序的一个问题可能是您可能将一个抽象方法标记为@Transactional,您正在覆盖该抽象方法并从抽象类实例中调用它。
例如来自 AbstractUserDetailsAuthenticationProvider 的 retreiveUser。该方法是从实例内部调用的(参见方法authenticate),因此无法通过AOP代理机制初始化事务。更多详情请查看@Transactional method calling another method without @Transactional anotation?
Spring 声明式事务模型使用 AOP 代理。所以 AOP 代理负责创建事务。仅当实例中的方法从实例外部调用时,AOP 代理才会处于活动状态。
【讨论】:
【参考方案4】:我遇到了同样的问题,原因是我在 web.xml 文件中的 OpenSessionInView
过滤器之前声明了 Spring Security 的过滤器。一旦我交换了它们,问题就消失了。
原因是在 OpenSessionInView
过滤器打开 Hibernate 会话之前调用了 Spring Security,因此没有打开会话。
【讨论】:
以上是关于使用事务包装 Spring Security 自定义身份验证提供程序的主要内容,如果未能解决你的问题,请参考以下文章
Spring Security 入门 我们在篇中已经谈到了默认的登录页面以及默认的登录账号和密码。 在这一篇中我们将自己定义登录页面及账号密码。 我们先从简单的开始吧:设置自定
遵循 Grails Spring Security Core 教程时出现“没有正在进行的事务”错误
Spring Security应用开发(05)自定义表单认证