挂毯覆盖身份验证器
Tapestry override Authenticator
我正在尝试为挂毯安全使用自定义验证器 (org.tynamo.security)。
我有一个自定义验证器
public class EnvironmentalRealmAuthenticator extends ModularRealmAuthenticator
并且在我的模块中我覆盖了 Tapestry 的默认验证器 (ModularRealmAuthenticator
):
public static void bind(final ServiceBinder binder) {
binder.bind(Authenticator.class, EnvironmentalRealmAuthenticator.class).withId("EnvironmentalRealmAuthenticator");
}
@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration<Class, Object> configuration, @Local final Authenticator override) {
configuration.add(Authenticator.class, override);
}
但是,这会导致缓存在注销时不会被清除 - 我怀疑这是由 Shiro 的 DefaultSecurityManager
检测身份验证器是否监听注销的方式引起的:
Authenticator authc = getAuthenticator();
if (authc instanceof LogoutAware) {
((LogoutAware) authc).onLogout(principals);
}
由于 EnvironmentalRealmAuthenticator
被绑定为 Tapestry 服务,它最初作为代理注入,因此 authc instanceof LogoutAware
产生 false
- 这就是默认 ModularRealmAuthenticator
的原因在 Tynamo 的 SecurityModule
中以不同的方式绑定:
// TYNAMO-155 It's not enough to identify ModularRealmAuthenticator by it's Authenticator interface only
// because Shiro tests if the object is an instanceof LogoutAware to call logout handlers
binder.bind(ModularRealmAuthenticator.class);
但是,当我尝试以这种方式覆盖我的 EnvironmentalRealmAuthenticator
时
binder.bind(EnvironmentalRealmAuthenticator.class).withId("EnvironmentalRealmAuthenticator");
这会导致以下异常:
Caused by: java.lang.IllegalStateException: Construction of service 'ServiceOverride' has failed due to recursion: the service depends on itself in some way. Please check org.apache.tapestry5.ioc.internal.services.ServiceOverrideImpl(Map) (at ServiceOverrideImpl.java:31) via org.apache.tapestry5.ioc.modules.TapestryIOCModule.bind(ServiceBinder) (at TapestryIOCModule.java:52) for references to another service that is itself dependent on service 'ServiceOverride'.
如果没有看到导致该异常的 setupOverrides
方法的最终版本,我无法确定。
但是,你试过这个吗:
public static void bind(final ServiceBinder binder) {
binder.bind(EnvironmentalRealmAuthenticator.class);
}
@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration<Class, Object> configuration, EnvironmentalRealmAuthenticator override) {
configuration.add(Authenticator.class, override);
}
我似乎找到了一个(相当老套的)方法。我没有覆盖 Authenticator
本身,而是覆盖了 WebSecuritymanager
:
public static void bind(final ServiceBinder binder) {
binder.bind(EnvironmentalRealmAuthenticator.class).withId("EnvironmentalRealmAuthenticator");
binder.bind(WebSecurityManager.class, EnvironmentalSecurityManager.class).withId("EnvironmentalSecurityManager");
}
@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration<Class, Object> configuration, @Local final WebSecurityManager override) {
configuration.add(WebSecurityManager.class, override);
}
这样我就不必将 EnvironmentalRealmAuthenticator
与其接口绑定。为了能够识别新的 Authenticator
我注释了模块:
@Marker(Primary.class)
EnvironmentalSecurityManager
的实现如下所示:
/**
* Used to properly (and uniquely) identify the authenticator (without having to override it)
*/
public class EnvironmentalSecurityManager extends TapestryRealmSecurityManager {
private final Logger logger = LoggerFactory.getLogger(EnvironmentalSecurityManager.class);
/**
* Mind the @Primary annotation, used to identify the EnvironmentalRealmAuthenticator
*/
public EnvironmentalSecurityManager(final @Primary Authenticator authenticator, final SubjectFactory subjectFactory, final RememberMeManager rememberMeManager, final Collection<Realm> realms) {
super(authenticator, subjectFactory, rememberMeManager, realms);
logger.debug("Created EnvironmentalSecurityManager - class of authenticator is {}", authenticator.getClass());
}
}
这样我就可以保证使用正确的 Authenticator
而不必实际覆盖它。
我正在尝试为挂毯安全使用自定义验证器 (org.tynamo.security)。
我有一个自定义验证器
public class EnvironmentalRealmAuthenticator extends ModularRealmAuthenticator
并且在我的模块中我覆盖了 Tapestry 的默认验证器 (ModularRealmAuthenticator
):
public static void bind(final ServiceBinder binder) {
binder.bind(Authenticator.class, EnvironmentalRealmAuthenticator.class).withId("EnvironmentalRealmAuthenticator");
}
@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration<Class, Object> configuration, @Local final Authenticator override) {
configuration.add(Authenticator.class, override);
}
但是,这会导致缓存在注销时不会被清除 - 我怀疑这是由 Shiro 的 DefaultSecurityManager
检测身份验证器是否监听注销的方式引起的:
Authenticator authc = getAuthenticator();
if (authc instanceof LogoutAware) {
((LogoutAware) authc).onLogout(principals);
}
由于 EnvironmentalRealmAuthenticator
被绑定为 Tapestry 服务,它最初作为代理注入,因此 authc instanceof LogoutAware
产生 false
- 这就是默认 ModularRealmAuthenticator
的原因在 Tynamo 的 SecurityModule
中以不同的方式绑定:
// TYNAMO-155 It's not enough to identify ModularRealmAuthenticator by it's Authenticator interface only
// because Shiro tests if the object is an instanceof LogoutAware to call logout handlers
binder.bind(ModularRealmAuthenticator.class);
但是,当我尝试以这种方式覆盖我的 EnvironmentalRealmAuthenticator
时
binder.bind(EnvironmentalRealmAuthenticator.class).withId("EnvironmentalRealmAuthenticator");
这会导致以下异常:
Caused by: java.lang.IllegalStateException: Construction of service 'ServiceOverride' has failed due to recursion: the service depends on itself in some way. Please check org.apache.tapestry5.ioc.internal.services.ServiceOverrideImpl(Map) (at ServiceOverrideImpl.java:31) via org.apache.tapestry5.ioc.modules.TapestryIOCModule.bind(ServiceBinder) (at TapestryIOCModule.java:52) for references to another service that is itself dependent on service 'ServiceOverride'.
如果没有看到导致该异常的 setupOverrides
方法的最终版本,我无法确定。
但是,你试过这个吗:
public static void bind(final ServiceBinder binder) {
binder.bind(EnvironmentalRealmAuthenticator.class);
}
@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration<Class, Object> configuration, EnvironmentalRealmAuthenticator override) {
configuration.add(Authenticator.class, override);
}
我似乎找到了一个(相当老套的)方法。我没有覆盖 Authenticator
本身,而是覆盖了 WebSecuritymanager
:
public static void bind(final ServiceBinder binder) {
binder.bind(EnvironmentalRealmAuthenticator.class).withId("EnvironmentalRealmAuthenticator");
binder.bind(WebSecurityManager.class, EnvironmentalSecurityManager.class).withId("EnvironmentalSecurityManager");
}
@Contribute(ServiceOverride.class)
public static void setupOverrides(final MappedConfiguration<Class, Object> configuration, @Local final WebSecurityManager override) {
configuration.add(WebSecurityManager.class, override);
}
这样我就不必将 EnvironmentalRealmAuthenticator
与其接口绑定。为了能够识别新的 Authenticator
我注释了模块:
@Marker(Primary.class)
EnvironmentalSecurityManager
的实现如下所示:
/**
* Used to properly (and uniquely) identify the authenticator (without having to override it)
*/
public class EnvironmentalSecurityManager extends TapestryRealmSecurityManager {
private final Logger logger = LoggerFactory.getLogger(EnvironmentalSecurityManager.class);
/**
* Mind the @Primary annotation, used to identify the EnvironmentalRealmAuthenticator
*/
public EnvironmentalSecurityManager(final @Primary Authenticator authenticator, final SubjectFactory subjectFactory, final RememberMeManager rememberMeManager, final Collection<Realm> realms) {
super(authenticator, subjectFactory, rememberMeManager, realms);
logger.debug("Created EnvironmentalSecurityManager - class of authenticator is {}", authenticator.getClass());
}
}
这样我就可以保证使用正确的 Authenticator
而不必实际覆盖它。