有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Tapestry重写验证器

我正在尝试为tapestry安全性使用自定义验证器(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-这就是为什么在Tynamo的SecurityModule中以不同的方式绑定默认ModularRealmAuthenticator

// 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'.


共 (2) 个答案

  1. # 1 楼答案

    如果没有看到导致该异常的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);
    }
    
  2. # 2 楼答案

    我似乎找到了一个(相当老套的)方法。我不是重写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,而不必实际重写它