简体   繁体   English

挂毯覆盖身份验证器

[英]Tapestry override Authenticator

I am trying to use a custom authenticator for tapestry-security ( org.tynamo.security ).我正在尝试为挂毯安全性 ( org.tynamo.security ) 使用自定义身份验证器。

I have a custom authenticator我有一个自定义验证器

public class EnvironmentalRealmAuthenticator extends ModularRealmAuthenticator

And in my module I override the default authenticator of Tapestry ( 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);
}

However, this causes the cache to not be cleared on logout - I have the suspicion that this is caused by the way the DefaultSecurityManager of Shiro detects if the authenticator listens to logouts:但是,这会导致缓存在注销时不会被清除 - 我怀疑这是由 Shiro 的DefaultSecurityManager检测身份验证器是否监听注销的方式引起的:

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

As the EnvironmentalRealmAuthenticator is bound as a Tapestry service, it is initially injected as a proxy and hence authc instanceof LogoutAware yields false - that's why the default ModularRealmAuthenticator is bound in a different way in the SecurityModule of Tynamo:由于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);

However, when I try to override my EnvironmentalRealmAuthenticator that way但是,当我尝试以这种方式覆盖我的EnvironmentalRealmAuthenticator

binder.bind(EnvironmentalRealmAuthenticator.class).withId("EnvironmentalRealmAuthenticator");

this results in the following exception:这导致以下异常:

Caused by: java.lang.IllegalStateException: Construction of service 'ServiceOverride' has failed due to recursion: the service depends on itself in some way. Caused by: java.lang.IllegalStateException: 由于递归,服务“ServiceOverride”的构建失败:服务以某种方式依赖于自身。 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'. 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 ) 引用另一个本身依赖于服务“ServiceOverride”的服务。

I can't be sure without seeing the final version of your setupOverrides method that caused that exception.如果没有看到导致该异常的setupOverrides方法的最终版本,我无法确定。

But, have you tried this:但是,你有没有试过这个:

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);
}

I seem to have found a (rather hacky) way.我似乎找到了一种(相当古怪的)方法。 Instead of overriding the Authenticator itself, I override the WebSecuritymanager instead:我没有覆盖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);
}

That way I don't have to bind the EnvironmentalRealmAuthenticator with its interface.这样我就不必将EnvironmentalRealmAuthenticator与其接口绑定。 In order to be able to identify the new Authenticator I annotated the module:为了能够识别新的Authenticator ,我对模块进行了注释:

@Marker(Primary.class)

The implmentation of the EnvironmentalSecurityManager then looks like this: 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());
    }
}

That way I can guarantee that the correct Authenticator is used without actually having to override it.这样我就可以保证使用正确的Authenticator而不必实际覆盖它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM