0

我正在尝试使用自定义身份验证器进行挂毯安全性(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);
}

但是,这会导致缓存在注销时不会被清除——我怀疑这是由DefaultSecurityManagerShiro 检测身份验证器是否监听注销的方式引起的:

Authenticator authc = getAuthenticator();
if (authc instanceof LogoutAware) {
    ((LogoutAware) authc).onLogout(principals);
}

由于EnvironmentalRealmAuthenticator绑定为 Tapestry 服务,它最初作为代理注入并因此authc instanceof LogoutAware产生false- 这就是为什么默认值在TynamoModularRealmAuthenticator中以不同的方式绑定: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");

这会导致以下异常:

原因:java.lang.IllegalStateException:服务“ServiceOverride”的构造由于递归而失败:服务以某种方式依赖于自身。请通过 org.apache.tapestry5.ioc.modules.TapestryIOCModule.bind(ServiceBinder) (在 TapestryIOCModule.java:52) 检查 org.apache.tapestry5.ioc.internal.services.ServiceOverrideImpl(Map) (在 ServiceOverrideImpl.java:31) ) 用于引用另一个本身依赖于服务“ServiceOverride”的服务。

4

2 回答 2

0

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);
}
于 2020-10-29T08:08:45.940 回答
0

我似乎找到了一种(相当老套的)方法。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)

then的实现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的,而不必实际覆盖它。

于 2020-10-30T13:39:16.077 回答