Java Web应用程序:使用自定义的境界

问题描述:

我在写这需要通过web服务进行登录Java Web应用程序。当然,没有与我使用(GlassFish v2中)应用服务器提供的领域可以做的伎俩。因此,我不得不写我自己的。但是看来,这是我写的境界实现完全依赖于GLASSFISH并且不能被用作是在任何其他应用程序服务器

I'm writing a java web application which need to perform login through a webservice. Of course, none of the realms supplied with the application server I'm using (glassfish v2) can do the trick. I therefore had to write my own. It seems however, that the realm implementation that I wrote is completely tied to glassfish and cannot be used as is in any other application servers.

有没有办法实现定制领域中的任何标准或广泛支持的方式?它是在任何可能的方式来部署从一个.war那个境界,还是它总是需要从服务器的自己的类路径装?

Is there any standard or widely supported way to implement a custom Realm? Is it in any way possible to deploy that realm from a .war, or does it always need to be loaded from the server's own classpath?

注:下面的答案是唯一有效的对Java EE 5.被带到了我的注意其他的答案之一,Java EE 6的不支持这一点。所以,如果你使用的是Java EE 6,不读这个答案,但看了其他相关的答案。

NOTE: The answer below is only valid for Java EE 5. As was brought to my attention in one of the other answers, Java EE 6 does support this. So if you're using Java EE 6, don't read this answer, but read the other relevant answer.

这是我自己的研究,并从回应这个问题,我找到了答案是:虽然JAAS是一个标准的接口,有写,部署和集成JAAS境界+登录模块在各种应用服务器没有统一的方法。

From my own research and from the responses to this question the answer I found is the following: Although JAAS is a standard interface, there is no uniform way to write, deploy and integrate a JAAS Realm + LoginModule in various application servers.

GlassFish v2中要求你延长一些实现登录模块或领域本身它自己的内部类。因为LoginModule接口的很多方法都被标记决赛中GlassFish的超但是,您可以不能自定义整个登录过程。自定义LoginModule与境界类必须放置在AS类路径(未应用程序的),并且该领域必须手动注册(没有来自的.war可能部署)。

Glassfish v2 requires you to extend some of its own internal classes that implement LoginModule or Realm themselves. You can however not customize the whole login process because many methods of the LoginModule interface are marked final in Glassfish's superclass. The custom LoginModule and Realm classes must be placed in the AS classpath (not the application's), and the realm must be manually registered (no deployment from the .war possible).

这种情况似乎是Tomcat的好一点,这将让你code你自己的境界与登录模块完全关闭,然后将其配置到应用服务器使用自己的JAASRealm(这将委托实际工作中你境界与登录模块的实现)。然而,即使tomcat的不允许从你的.war部署自定义领域。

The situation seems to be a bit better for Tomcat, which will let you code your own Realm and LoginModule completely, and then configure them into the application server using its own JAASRealm (which will delegate the actual work to your implementations of Realm and LoginModule). However, even tomcat doesn't allow deploying your custom realm from your .war.

请注意,没有应用程序服务器的出现了我的结果似乎是能够把所有的JAAS回调充分利用。所有这些似乎只支持基本的用户名+密码方案。如果你需要什么比这更复杂,那么你就需要找到不被你的Java EE容器管理的解决方案。

Note that none of the Application Servers that showed up my results seem to be able to take full advantage of all the JAAS Callbacks. All of them seem to only support the basic username+password scheme. If you need anything more complicated than that, then you will need to find a solution that is not managed by your Java EE container.

作为参考,因为它是在评论我的问题问,这里是code我写GlassfishV2。

For reference, and because it was asked for in the comments to my question, here is the code I wrote for GlassfishV2.

首先,这里的领域实现:

First of all, here's the Realm implementation:

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实现:

And then the LoginModule implementation:

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

最后,在领域已被捆绑到登录模块。这是在JAAS配置文件的水平,这在GlassFish v2中位于在YOURDOMAIN /配置/ login.conf中完成的。添加以下行以该文件的末尾:

finally, in the Realm has to be tied to the LoginModule. This is done at the JAAS configuration file level, which in glassfish v2 lies at yourDomain/config/login.conf. Add the following lines at the end of that file:

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

这是得到的东西为我工作在GlassFish。此外,该解决方案不能跨应用服务器移植,但据我所知,没有现成的便携式解决方案。

This is what got things working for me on glassfish. Again, this solution is not portable across application servers, but as far as I can tell, there is no existing portable solution.