当前位置:  开发笔记 > 运维 > 正文

Java Web应用程序:使用自定义领域

如何解决《JavaWeb应用程序:使用自定义领域》经验,为你挑选了2个好方法。

我正在编写一个需要通过webservice登录的java Web应用程序.当然,我使用的应用程序服务器(glassfish v2)提供的领域都不能解决问题.因此,我必须自己写.但是,我写的领域实现似乎完全依赖于glassfish,不能像任何其他应用程序服务器那样使用.

是否有任何标准或广泛支持的方式来实现自定义Realm?是以任何方式从.war部署该领域,还是总是需要从服务器自己的类路径加载?



1> LordOfThePig..:

注意:下面的答案仅对Java EE 5有效.在其他一个答案中引起我的注意,Java EE 6确实支持这一点.因此,如果您使用的是Java EE 6,请不要阅读此答案,而应阅读其他相关答案.

从我自己的研究和对这个问题的回答中我得到的答案如下:虽然JAAS是一个标准接口,但是没有统一的方法来在各种应用服务器中编写,部署和集成JAAS Realm + LoginModule.

Glassfish v2要求您扩展一些自己实现LoginModule或Realm的内部类.但是,您可以不自定义整个登录过程,因为LoginModule接口的许多方法都在Glassfish的超类中标记为final.自定义LoginModule和Realm类必须放在AS类路径中(而不是应用程序),并且必须手动注册域(不可能从.war部署).

Tomcat的情况似乎好一点,它可以让你完全编写自己的Realm和LoginModule代码,然后使用自己的JAASRealm将它们配置到应用程序服务器中(它将实际工作委托给你的Realm和LoginModule实现) .但是,即使tomcat也不允许从.war部署自定义领域.

请注意,没有显示我的结果的应用程序服务器似乎能够充分利用所有JAAS回调.所有这些似乎只支持基本的用户名+密码方案.如果您需要更复杂的东西,那么您需要找到一个不受Java EE容器管理的解决方案.

作为参考,并且因为在我的问题的评论中要求它,这是我为GlassfishV2编写的代码.

首先,这是Realm的实现:

public class WebserviceRealm extends AppservRealm {

private static final Logger log = Logger.getLogger(WebserviceRealm.class.getName());

private String jaasCtxName;
private String hostName;
private int port;
private String uri;

@Override
protected void init(Properties props) throws BadRealmException, NoSuchRealmException {
    _logger.info("My Webservice Realm : init()");

    // read the configuration properties from the user-supplied properties,
    // use reasonable default values if not present
    this.jaasCtxName = props.getProperty("jaas-context", "myWebserviceRealm");
    this.hostName = props.getProperty("hostName", "localhost");
    this.uri = props.getProperty("uri", "/myws/EPS");

    this.port = 8181;
    String configPort = props.getProperty("port");
    if(configPort != null){
        try{
            this.port = Integer.parseInt(configPort);
        }catch(NumberFormatException nfe){
            log.warning("Illegal port number: " + configPort + ", using default port (8181) instead");
        }
    }
}

@Override
public String getJAASContext() {
    return jaasCtxName;
}

public Enumeration getGroupNames(String string) throws InvalidOperationException, NoSuchUserException {
    List groupNames = new LinkedList();
    return (Enumeration) groupNames;
}

public String getAuthType() {
    return "My Webservice Realm";
}

public String getHostName() {
    return hostName;
}

public int getPort() {
    return port;
}

public String getUri() {
    return uri;
}
}

然后是LoginModule实现:

public class WebserviceLoginModule extends AppservPasswordLoginModule {

// all variables starting with _ are supplied by the superclass, and must be filled
// in appropriately

@Override
protected void authenticateUser() throws LoginException {
    if (_username == null || _password == null) {
        throw new LoginException("username and password cannot be null");
    }

    String[] groups = this.getWebserviceClient().login(_username, _password);

    // must be called as last operation of the login method
    this.commitUserAuthentication(groups);
}

@Override
public boolean commit() throws LoginException {
    if (!_succeeded) {
        return false;
    }

    // fetch some more information through the webservice...

    return super.commit();
}

private WebserviceClient getWebserviceClient(){
    return theWebserviceClient;
}
}

最后,在Realm中必须绑定到LoginModule.这是在JAAS配置文件级别完成的,在glassfish v2中位于yourDomain/config/login.conf.在该文件的末尾添加以下行:

myWebserviceRealm { // use whatever String is returned from you realm's getJAASContext() method
    my.auth.login.WebserviceLoginModule required;
};

这就是玻璃鱼让我感觉有用的东西.同样,这个解决方案不能跨应用程序服务器移植,但据我所知,没有现有的便携式解决方案.



2> Arjan Tijms..:

是否有任何标准或广泛支持的方式来实现自定义Realm?是以任何方式从.war部署该领域,还是总是需要从服务器自己的类路径加载?

绝对有一种实现自定义Realm的标准方法,或者更一般地说是自定义身份验证模块.这可以通过JASPIC/JASPI/JSR 196 SPI/API完成.JASPIC是任何完整Java EE 6实现的标准部分,但遗憾的是它不是Java EE 6 Web Profile的一部分.

然而,尽管JASPIC是Java EE 6的一部分,但供应商并未对其提供最佳支持.GlassFish和WebLogic似乎有很好的实现,JBoss AS和Geronimo有点问题.JBoss的主要工程师(Anil Saldhana)甚至声称他暂时拒绝激活 JASPIC .最近修复了Jboss AS 7.1中一些最严重的错误,但由于JBoss 7.1.x没有公开发布,JBoss AS 7.2还有一段时间了,这意味着至少在JBoss JASPIC上是麻烦.

另一个不幸的问题是实际的身份验证模块可能是标准化的,但是没有声明性的方式(读取XML文件)来配置它的标准化.

是以任何方式从.war部署该领域,还是总是需要从服务器自己的类路径加载?

使用JASPIC,验证模块('realm')确实可以从.war加载.我不是100%确定这是否由规范保证,而是我测试的4台服务器(GlassFish,WebLogic,Geronimo和JBoss AS),他们都支持这一点.遗憾的是,Geronimo在程序化注册中存在某种竞争条件,所以你需要通过两次热部署来实现一个丑陋的解决方案,但最后如果从.war加载模块的话.

从专有机制来看,至少JBoss AS始终支持从.war或.ear加载模块(例如org.jboss.security.auth.spi.AbstractServerLoginModule的子类).

我最近写了一篇关于这个话题的博客文章,里面有更多细节.

推荐阅读
小色米虫_524
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有