Jaas JDBC 身份验证

Jaas JDBC Authentication

我们的项目包含一个通过 RMI 协议调用 JEE 服务器的 JavaFX 应用程序。 我们使用 Payara 应用服务器,一个 Glassfish 分支。 我们想将 JAAS 与数据库一起使用来管理授予用户的身份验证和权限。

我们不明白如何将创建的 JDBC 领域与我们的应用程序绑定以与数据库交互。

我们能否以编程方式调用领域或直接查询数据库 here

启动 LoginContext 的服务:

@Stateless
public class AuthenticationService implements IAuthenticationService {
    @Override
    public boolean login(User user) {
        try {
            LoginContext lc = new LoginContext(
                "JDBCLoginModule",
                new JDBCCallbackHandler(user.getUsername(), user.getPassword())
            );

            lc.login();

            Subject subject = lc.getSubject();

            return true;

        } catch (LoginException ex) {
            ex.printStacktrace();
        }
        return false;
    }
}

登录模块:

public class JDBCLoginModule implements LoginModule {
    private Subject subject;
    private CallbackHandler callbackHandler;
    private Map sharedState;
    private Map options;

    private boolean succeeded = false;

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

    @Override
    public boolean login() throws LoginException {
        if (callbackHandler == null)
            throw new LoginException("The callbackHandler is null");

        Callback[] callbacks = new Callback[2];
        callbacks[0] = new NameCallback("name:");
        callbacks[1] = new PasswordCallback("password:", false);

        try {
            callbackHandler.handle(callbacks);
        } catch (IOException e) {
            throw new LoginException("IOException calling handle on callbackHandler");
        }
        catch (UnsupportedCallbackException e) {
            throw new LoginException("UnsupportedCallbackException calling handle on callbackHandler");
        }

        NameCallback nameCallback           = (NameCallback) callbacks[0];
        PasswordCallback passwordCallback   = (PasswordCallback) callbacks[1];

        String name = nameCallback.getName();
        String password = new String(passwordCallback.getPassword());

        // Call the JDBC Realm
        /*if ("myName".equals(name) && "myPassword".equals(password)) {
            succeeded = true;
            return succeeded;
        }
        else {
            succeeded = false;
            throw new FailedLoginException("Sorry! No login for you.");
        }*/
    }

    @Override
    public boolean commit() throws LoginException {
        return succeeded;
    }

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

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

回调处理程序:

public class JDBCCallbackHandler implements CallbackHandler {
    private final String username;
    private final String password;

    public JDBCCallbackHandler(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof NameCallback) {
                NameCallback nameCallback = (NameCallback) callbacks[i];
                nameCallback.setName(username);
            }
            else if (callbacks[i] instanceof PasswordCallback) {
                PasswordCallback passwordCallback = (PasswordCallback) callbacks[i];
                passwordCallback.setPassword(password.toCharArray());
            }
            else {
                throw new UnsupportedCallbackException(callbacks[i], "The submitted Callback is unsupported");
            }
        }
    }
}

我们在应用服务器上创建了一个 JDBC 领域: JDBC Realm Image

如果您期望通过调用 AuthenticationService#login 您将登录(验证)Java EE 服务器 (Payara),那么这绝对是错误的方法。

在调用 lc.login(); 之后,Java EE 服务器不会以任何方式知道该调用。使用 new 运算符实例化的随机 LoginContext 不会神奇地连接到 Java EE 环境。

如果您正在进行远程 EJB 调用,则需要为该调用提供身份验证数据(来自 JavaFx 应用程序),然后在 [=38] 中为(远程)EJB 配置身份验证=] 具体方式。与 Servlet 相反,Java EE 中没有标准方法来为 EJB 进行身份验证(对于 Servlet,您将为此使用 JASPIC)。

也没有所谓的标准LoginModule。 GlassFish 确实使用了 LoginModule 接口,但是使用的是 highly GlassFish 特定的方式。如果你只想使用 JDBC 领域(领域是这里 "identity store" 的另一个术语,它是 "login module" 的另一个术语)你 'only' 需要使用 glassfish 来配置它具体glassfish-ejb-jar.xml 文件。不幸的是,几乎没有人知道如何准确地做到这一点,但我认为您需要查看 ior-security-config 并从那里进行研究。

或者,您可以使用 ProgrammaticLogin class,它是等同于标准 HttpServletRequest#login 的 GlassFish 特定 EJB。

Java EE 6 Application Client login