Java Web应用程序:使用自定义领域
-
23-08-2019 - |
题
我正在写需要通过一个web服务执行的登录Java Web应用程序。当然,没有与我使用(是GlassFish v2)的应用服务器提供的领域可以做的伎俩。因此,我不得不写我自己。不过,看来这是我写领域中的执行完全依赖于GLASSFISH并且不能被用作是在任何其他应用程序服务器。
有没有办法实现定制领域中的任何标准或广泛支持的方式?它是在任何可能的方式来部署从一个.war那个境界,或者它总是需要从服务器的自己的类路径装?
解决方案
注:下面的答案是唯一有效的对Java EE 5,作为被带到了我的注意力在其他的答案之一,Java EE 6的不支持此功能。所以,如果你使用的是Java EE 6,不读这个答案,但看了其他相关的答案。
这是我自己的研究,并从应对这个问题,我找到了答案如下:虽然JAAS是一个标准的接口,有写,部署和集成JAAS境界+ LoginModule的各种应用服务器没有统一的办法。
GlassFish v2中要求你延长一些实现的LoginModule或领域本身它自己的内部类。因为LoginModule接口的很多方法都被标记决赛中GlassFish的超但是,您可以不能自定义整个登录过程。自定义LoginModule与境界类必须被放置在AS类路径(未应用程序的),并且该领域必须手动注册(没有来自可能的.war部署)。
这种情况似乎是Tomcat的好一点,这将让你彻底编写自己的境界和的LoginModule,然后利用自身JAASRealm(这将委托实际的工作,你的境界的实现将其配置到应用服务器和的LoginModule)。然而,即使Tomcat没有允许从部署的.war您的自定义的境界。
请注意,没有任何应用程序服务器是出现了我的结果似乎能够采取一切JAAS回调充分利用。所有这些似乎只支持基本的用户名+密码方案。如果你需要什么比这更复杂,那么你就需要找到不是由您的Java EE容器管理的解决方案。
有关引用,因为它是在评论我的问题问,这里是我写的GlassfishV2的代码。
首先,这里的领域实现:
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;
}
}
最后,在境界具有被束缚给LoginModule。这是在JAAS配置文件的水平,这GlassFish v2中的谎言在您的域/配置/ login.conf中完成。添加以下行在该文件的末尾:
myWebserviceRealm { // use whatever String is returned from you realm's getJAASContext() method
my.auth.login.WebserviceLoginModule required;
};
这是什么得到的东西为我工作在GlassFish。再次,这种解决方案不能跨应用服务器的便携式,但据我所知,没有任何现有的便携式解决方案。
其他提示
是否有实现自定义任何标准或广泛的支持方式 领域?它是在任何可能的方式来从一个.war部署那个境界,或 它总是需要从服务器的自己的类路径装?
有绝对是实现自定义域,或在更一般的术语定制认证模块的标准方式。这可以通过 JASPIC / JASPI / JSR 196 SPI / API 来完成。 JASPIC是任何完整的Java EE 6实现的一个标准部分,但Java EE 6 Web Profile的不幸不是一部分。
然而,尽管JASPIC是的Java EE 6的一部分,它没有被最佳地由供应商所支持。 GlassFish和的WebLogic似乎有很好的实现,JBoss应用服务器和Geronimo是有点难度。从JBoss的首席工程师对这个话题(阿尼尔Saldhana)甚至说,他拒绝默认一来激活JASPIC >的时刻。一些在JBoss中最严重的错误的AS 7.1已经最近固定,但也有不公开发布JBoss的7.1.x排定了和JBoss AS 7.2还有一段时间远则意味着截至目前至少在JBoss JASPIC是麻烦的。
另一个不幸问题是,实际的认证模块可以标准化,但没有声明的方式(读取XML文件)来配置它多数民众赞成标准化。
时它在任何可能的方式来部署从一个.war该领域,或者它 总是需要从服务器的自己的类路径装?
通过JASPIC,认证模块(“境界”)确实可以从一个.war加载。我不是100%肯定这是否是通过规范保证,但我测试(GlassFish中,WebLogic中,Geronimo和JBoss应用服务器)的4台服务器,它们都支持这一点。 Geronimo的不幸有某种在其纲领性注册竞争条件,所以你需要做一个热部署两次丑陋的解决办法,但它到底,如果它来自的.war加载模块。
作为专有机制,至少JBoss应用服务器始终支持从加载将.war或的.ear的模块(例如一个org.jboss.security.auth.spi.AbstractServerLoginModule的子类)。
我最近写了一篇关于该主题的博客帖子具有更多一些的信息。
因为境界不是应用程序工件可以从未部署从WAR境界,它是一个容器工件(因此,短语“基于容器的安全性”)。你可以配置你的应用程序使用特定的领域作为容器提供,但应用程序不能在此提供本身。
这是说,所有的容器都不同,而这些领域都是不可移植的,简单的常识会降低差异的必要胶水代码的点点滴滴与容器整合,如果你正在寻找的便携性。
有有一个快速看一下太阳的文档,它看起来像你必须写一个扩展他们的应用程序服务器的特定类别的定义LoginModule。这似乎有点倒退到我和Glassfish的限制。
如果你想使这个更便于携带,我建议把大部分实施中对标准的JavaEE接口(S)开发的自定义LoginModule,然后有GlassFish特有的薄实现层委托给标准便携式实现。
查看 Sun公司关于这个主题的文章 强>
我从来没有真正做过这自己,但我很有信心每个AS可让您为它注册一个新的领域(安全域)的选项。
这可能不会是100%,便携,并为每个你可能需要一个不同的XML配置,但基本上,没有理由对代码有什么不同。