5

我是 Vaadin 的新手。在此之前,我制作了一个 JSF Web 应用程序。我有一个 ManagedBean 执行用户的登录。我使用了一个安全领域来委派凭据的实际验证。

我如何在 Vaadin 中执行此操作?有最佳实践吗?我正处于将一些东西放在一起的地步,但必须有某种标准程序,不是吗!?我找到了一些关于此的教程,但主要使用 Spring(我想使用 EJB)。此外,每个教程似乎都不必要地复杂。

对于如此常见的事情,必须有一些简单+结论性的教程。

4

3 回答 3

3

这是我能找到的唯一一篇关于如何使用 JAAS 保护 Vaadin 应用程序的 Vaadin 官方文章。我的意思是本地或官方 Vaadin 安全化。如果您使用 Spring security、Shiro 搜索一下,您会发现更多信息,但纯 ESB 使用 JAAS。我同意这篇文章不足以学习如何设置应用程序。我在这里分享我的经验:

1. Vaadin CDI 扩展:

<!-- Vaadin Official DI support. -->
<dependency>
  <groupId>com.vaadin</groupId>
  <artifactId>vaadin-cdi</artifactId>
  <version>1.0.0.alpha2</version>
</dependency>

2. 了解JAAS

我建议您通过阅读概述文章来了解 JAAS 在非 vaadin 应用程序中的工作原理,因为 JAAS 依赖于服务器应用程序提供者(TomEE、Jboss、Wildfly、Glasfish)都有不同的配置设置。在这里,您将找到使用 Tomee的概念证明。

3. 开发您自己的登录模块。

如果您决定创建一个自定义登录模块,例如:

public class MyLoginModule implements LoginModule {
private CallbackHandler handler;
private Subject subject;
private UserPrincipal userPrincipal;
private RolePrincipal rolePrincipal;
private String login;
private List<String> userGroups;
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
Map<String, ?> options) {
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 name = ((NameCallback) callbacks[0]).getName();
String password = String.valueOf(((PasswordCallback) callbacks[1]).getPassword());
// Here we validate the credentials against some
// authentication/authorization provider.
// It can be a Database, an external LDAP, a Web Service, etc.
// For this tutorial we are just checking if user is "user123" and
// password is "pass123"
if (name != null && name.equals("admin") && password != null && password.equals("admin")) {
login = name;
userGroups = new ArrayList<String>();
userGroups.add("admin");
return true;
}
// If credentials are NOT OK we throw a LoginException
throw new LoginException("Authentication failed");
} catch (IOException e) {
throw new LoginException(e.getMessage());
} catch (UnsupportedCallbackException e) {
throw new LoginException(e.getMessage());
}
}
@Override
public boolean commit() throws LoginException {
userPrincipal = new UserPrincipal(login);
subject.getPrincipals().add(userPrincipal);
if (userGroups != null && userGroups.size() > 0) {
for (String groupName : userGroups) {
rolePrincipal = new RolePrincipal(groupName);
subject.getPrincipals().add(rolePrincipal);
}
}
return true;
}
@Override
public boolean abort() throws LoginException {
return false;
}
@Override
public boolean logout() throws LoginException {
subject.getPrincipals().remove(userPrincipal);
subject.getPrincipals().remove(rolePrincipal);
return true;
}
}

在应用程序的 META-INF/context.xml 中引用它。此设置适用于 TomEE,但对于 glashfish 或其他必须类似。

<?xml version="1.0" encoding="UTF-8"?>
<Context>
  <Realm className="org.apache.catalina.realm.JAASRealm" appName="myrealm" userClassNames="net.sf.jaas.auth.UserPrincipal"
    roleClassNames="net.sf.jaas.auth.RolePrincipal" />
</Context>

请注意,userClassNames 和 roleClassNames 只是简单的 Java Pojo,但必须实现 java.security.Principal;

3. 在您的 Vaadin 登录视图中启用 JAAS

使用 Vaadin TextField 和 Password 定义您最喜欢的登录表单,并在您的 doLoginEvent() 中定义对 JAAS 的引用。每当调用 JaasAccessControl.login 时,都会创建一个新的 LoginModule 实例。

  import com.vaadin.cdi.access.JaasAccessControl;
  try {
            JaasAccessControl.login(loginEvent.getUsername(), loginEvent.getPassword());
            logger.info("User {} authenticated", getPrincipalName());
            navigator.navigateTo(Main.NAME);
        } catch (Exception e) {
            Notification.show("Error logging in", Type.ERROR_MESSAGE);
            logger.error(e.getMessage(), e);
        }

4. 使用您登录用户的信息。

每当用户通过 JAAS 登录过滤器时。它将在他的请求上下文中提供一个标识他的类。此类称为 Principal(您之前在 LoginModule 类中设置的类)。

public boolean isUserInRole(String role) {
        return JaasAccessControl.getCurrentRequest().isUserInRole(role);
    }

    public String getPrincipalName() {
        Principal principal = JaasAccessControl.getCurrentRequest().getUserPrincipal();
        if (principal != null) {
            return principal.getName();
        }

        return null;
    }

    public boolean isUserSignedIn() {
        Principal principal = JaasAccessControl.getCurrentRequest().getUserPrincipal();
        return principal != null;
    }

5. LoginModule 的替代方案

创建自定义登录模块不是强制性的,通常 Java EE 提供者作为 Tomee 提供很少的实现。在某些数据库表中,基于属性文件的身份验证。查看Tomee 文档 JAAS以查看一些示例:

6. 在 TomEE 中启用 JAAS 你需要创建一个引用你 LoginModule 的 jaas.config 文件,例如:

filename: jaas.config 
myrealm{
    net.sf.jaas.MyLoginModule required;
};

然后使用此参数启动应用程序服务器:

-Djava.security.auth.login.config=E:/apache-tomee-jaxrs-1.6.0.2/conf/jaas.config

如果你想看看这个概念的证明。看看这个例子,它使用了 Tomee、Vaadin 7、JAAS、

于 2015-01-29T12:39:59.173 回答
1

几个月前我遇到了同样的问题。我当时无法弄清楚它是如何工作的,所以我查看了 spring 插件,现在我正在使用 Vaadin 登录表单和 spring security

于 2013-07-23T07:55:22.923 回答
1

此处LoginForm提供了使用 JAAS、Vaadin 8、Vaadin CDI 插件和内置插件的完整示例,步骤如下:

  1. 启用 Vaadin CDI 插件pom.xml
  2. 在 Vaadin UI中使用注释启用CDI并配置@CDIUINavigator
  3. 通过添加注释(或任何其他注释)在 CDI 视图中启用授权@RolesAllowedjavax.annotation.security
  4. 实现一个派生自内置并用于验证用户的登录视图。LoginFormJaasAccessControl

一旦你弄清楚这些部分是如何组合在一起的,这实际上是一种相当不错、流畅的体验。

Vaadin wiki中有一篇较长的文章解释了如何将数据库支持的身份验证与 JAAS 一起使用。

于 2017-03-11T12:29:08.340 回答