簡體   English   中英

是否可以在tomcat中創建自定義域而無需將jar添加到lib文件夾?

[英]Is it possible to create custom realm in tomcat without adding jar to lib folder?

我想用自定義身份驗證制作Web應用程序。 但是我必須將Realm添加到server.xml中。 這需要我將jar添加到tomcat lib文件夾中。 我能把所有內容保存在我的戰爭文件中嗎 怎么樣?

感謝名單!

遺憾的是,不可能在Tomcat中從WAR部署自定義領域。 必須可以在CATALINA_HOME中訪問自定義領域實現。 它被視為容器工件,而不是應用程序工件。

我只能想到這三個選項:

選項1:移動到另一個Web應用程序服務器

至少GlassfishJBoss AS支持從WAR部署的自定義領域。

選項2:不要使用自定義領域

Tomcat 8現在允許自定義憑證處理。 如果可能足以滿足您的需求,而不是使用自定義的解決方案:

Apache Tomcat 8.0.15可用

[...]

通過新的CredentialHandler接口向Realms添加可插入密碼派生支持。

請參閱http://www.tomcatexpert.com/blog/2014/11/14/apache-tomcat-8015-available

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

選項3:處理它

如果您的解決方案已按預期工作,您可能希望保留它並直接處理部署問題。

另一個不錯的選擇是使用Tomcat的股票JAASRealmorg.apache.catalina.realm.JAASRealm )來實現自定義JAAS LoginModule 這種方法的JAASRealm是可以通過類路徑源configFile值配置JAASRealm以便所有內容都捆綁在WAR文件中。 來自https://tomcat.apache.org/tomcat-9.0-doc/config/realm.html#JAAS_Realm_-_org.apache.catalina.realm.JAASRealm關於configFile領域屬性:

與此Realm一起使用的JAAS配置文件的名稱。 將使用ClassLoader#getResource(String)搜索它,以便可以將配置捆綁在Web應用程序中。 如果未指定,將使用缺省JVM全局JAAS配置。

這是所有部分的簡單示例:

User.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 + '}';
  }
}

Role.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 + '}';
  }
}

DemoLoginModule.java

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

的jaas.config

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

以上所有內容都可以打包在一個jar中,並作為庫包含在另一個應用程序中。 該應用程序可以使用以下tomcat領域配置使用JAAS支持的身份驗證:

web.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>

的context.xml

<?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>

jaas.config文件將在類路徑中找到(Web應用程序的本地或jar依賴項)。 在給定我們簡單的DemoLoginModule實現的情況下,通過admin / password憑證進行身份驗證后,將可以訪問受admin角色保護的任何資源(即任何帶有pattern /admin/* url)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM