我是Vaadin的新手。 在此之前,我製作了一個JSF Web應用程序。 我有一個ManagedBean執行用戶的登錄。我使用安全領域來委派實際的證書驗證。Vaadin身份驗證和Auhorization
我如何在Vaadin做到這一點?有最佳做法嗎? 我在一個點上,我只是把一些東西放在一起,但必須有某種標準程序,不應該! 我發現了一些教程,但大多使用Spring(我想使用EJB)。另外,每個教程似乎並不複雜。
對於如此普遍的事情,必須有一些簡單+確定的教程。
我是Vaadin的新手。 在此之前,我製作了一個JSF Web應用程序。 我有一個ManagedBean執行用戶的登錄。我使用安全領域來委派實際的證書驗證。Vaadin身份驗證和Auhorization
我如何在Vaadin做到這一點?有最佳做法嗎? 我在一個點上,我只是把一些東西放在一起,但必須有某種標準程序,不應該! 我發現了一些教程,但大多使用Spring(我想使用EJB)。另外,每個教程似乎並不複雜。
對於如此普遍的事情,必須有一些簡單+確定的教程。
這是唯一的Vaadin官方文章,關於如何保護我能找到的Vaadin aplication using JAAS。我的意思是本地或官方Vaadin Securization。如果你使用Spring安全性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的proof of concept。
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.啓用JAAS到您的Vaadin登錄查看
定義自己喜歡的登錄表單,使用Vaadin TextField和密碼,並在您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 documentation 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
如果您想查看此概念的證明。 Checkout this example,它使用Tomee不同,Vaadin 7,JAAS,
幾個月前我遇到了同樣的問題。當時我無法弄清楚它是如何工作的,所以我去了春天的adddon,現在我正在使用Vaadin登錄表單和彈簧安全
使用JAAS不同,Vaadin 8所述的完整的例子不同,Vaadin CDI附加和內置LoginForm
可用here,步驟如下:
pom.xml
@CDIUI
註釋和配置Navigator
@RolesAllowed
註釋啓用authorization in a CDI view(或任何其它javax.annotation.security
註釋)LoginForm
並使用JaasAccessControl
來驗證用戶。一旦你弄清楚這些零件如何組合在一起,它實際上是一個相當不錯的流暢體驗。
Vaadin wiki中有一篇較長的文章解釋瞭如何在JAAS中使用數據庫支持的認證。
非常感謝您的回答。不過,我會留下這個問題,因爲有人可能會想出一個純粹的Vaadin解決方案。 – fancy 2013-07-24 06:33:05