是否可以在tomcat中创建自定义域而无需将jar添加到lib文件夹?

时间:2015-03-25 07:25:50

标签: java tomcat authentication

我想使用自定义身份验证制作网络应用。但是我必须将Realm添加到server.xml中。这需要我将jar添加到tomcat lib文件夹中。我能把所有内容保存在我的战争文件中吗怎么样?

感谢名单!

2 个答案:

答案 0 :(得分:5)

不幸的是,不可能在Tomcat中从WAR部署自定义领域。必须可以在CATALINA_HOME中访问自定义领域实现。它被视为容器工件,而不是应用程序工件。

我只能想到这三个选项:

选项1:移至另一个Web应用程序服务器

至少 Glassfish JBoss AS 支持从WAR部署的自定义域。

选项2:不要使用自定义领域

Tomcat 8现在允许自定义凭据处理。如果可能足以满足您的需求,而不是使用自定义的真实解决方案:

  

Apache Tomcat 8.0.15可用

     

[...]

     

通过新增功能为Realms添加可插拔密码派生支持   CredentialHandler接口。

请参阅http://www.tomcatexpert.com/blog/2014/11/14/apache-tomcat-8015-available

https://tomcat.apache.org/tomcat-8.0-doc/config/credentialhandler.html

选项3:处理它

如果您的解决方案已按预期工作,您可能希望保留它并直接处理部署问题。

答案 1 :(得分:0)

另一个好的选择是使用Tomcat的股票const content = '<p>' + '<strong>Summary</strong><br />Some text with <strong>HTML</strong> tags...<br /><br />' + '<strong>Keywords</strong> keyword1, keyword2,...<br /><br />' + '</p>'; var summary = content.match('<strong>Summary</strong><br />(.*?)<br /><br />'); var keywords = content.match('<strong>Keywords</strong> (.*?)<br /><br />'); alert (summary[1]); alert (keywords[1]); JAASRealm)来实现自定义JAAS org.apache.catalina.realm.JAASRealm。这种方法的优点在于,可以通过源自LoginModule的类路径值来配置JAASRealm,以便所有内容都捆绑在WAR文件中。来自https://tomcat.apache.org/tomcat-9.0-doc/config/realm.html#JAAS_Realm_-_org.apache.catalina.realm.JAASRealmconfigFile领域属性:

  

与此领域一起使用的JAAS配置文件的名称。将使用ClassLoader#getResource(String)进行搜索,因此可以将配置捆绑在Web应用程序中。如果未指定,将使用默认的JVM全局JAAS配置。

这是所有部分的简单示例:

User.java

configFile

Role.java

package com.company.jaas;

import java.security.Principal;

public class User implements Principal {
  private final String username;

  public User(String username) {
    this.username = username;
  }

  public String getUsername() {
    return username;
  }

  @Override
  public String getName() {
    return getUsername();
  }

  @Override
  public String toString() {
    return "User{" + "username=" + username + '}';
  }
}

DemoLoginModule.java

package com.company.jaas;

import java.security.Principal;

public class Role implements Principal {
  private final String name;

  public Role(String name) {
    this.name = name;
  }

  @Override
  public String getName() {
    return name;
  }

  @Override
  public String toString() {
    return "Role{" + "name=" + name + '}';
  }
}

jaas.config

package com.company.jaas;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

public class DemoLoginModule implements LoginModule {
  private CallbackHandler handler;
  private Subject subject;
  private User user;
  private List<Role> roles;

  @Override
  public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
    this.handler = callbackHandler;
    this.subject = subject;
  }

  @Override
  public boolean login() throws LoginException {
    Callback[] callbacks = new Callback[2];
    callbacks[0] = new NameCallback("login");
    callbacks[1] = new PasswordCallback("password", true);

    try {
      handler.handle(callbacks);
      String username = ((NameCallback) callbacks[0]).getName();
      String password = String.valueOf(((PasswordCallback) callbacks[1]).getPassword());

      // todo: perform real validation here (using any desired mechanism)
      if ("admin".equalsIgnoreCase(username) && "password".equals(password)) {
        user = new User(username);
        roles = List.of(new Role("admin"));
        return true;
      }

      throw new FailedLoginException("Authentication failed");
    }
    catch (IOException | UnsupportedCallbackException ex) {
      throw new LoginException(ex.getMessage());
    }
  }

  @Override
  public boolean commit() throws LoginException {
    subject.getPrincipals().add(user);
    subject.getPrincipals().addAll(roles);
    return true;
  }

  @Override
  public boolean abort() throws LoginException {
    return false;
  }

  @Override
  public boolean logout() throws LoginException {
    subject.getPrincipals().remove(user);
    subject.getPrincipals().removeAll(roles);
    return true;
  }
}

以上所有内容都可以打包在一个jar中,并作为一个库包含在另一个应用程序中。该应用程序可以通过使用以下tomcat领域配置来使用JAAS支持的身份验证:

web.xml

DemoAuth {
  com.company.jaas.DemoLoginModule required ;
};

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">

  <security-role>
    <role-name>admin</role-name>
  </security-role>

  <security-constraint>
    <web-resource-collection>
      <web-resource-name>action</web-resource-name>
      <url-pattern>/admin/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>admin</role-name>
    </auth-constraint>
  </security-constraint>

  <login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
      <form-login-page>/WEB-INF/jsp/login.jsp</form-login-page>
      <form-error-page>/WEB-INF/jsp/login-error.jsp</form-error-page>       
    </form-login-config>
  </login-config>

</web-app>

<?xml version="1.0" encoding="UTF-8"?> <Context path="/JaasDemo"> <Realm appName="DemoAuth" configFile="jaas.config" className="org.apache.catalina.realm.JAASRealm" userClassNames="com.company.jaas.User" roleClassNames="com.company.jaas.Role" /> </Context> 文件将在类路径中找到(在Web应用程序本地或在jar依赖项中)。只要使用我们简单的jaas.config实现,通过admin / password凭据进行身份验证,就可以访问受admin角色保护的任何资源(即,任何具有模式/admin/*的url)。