Java 如何在 Vaadin 中执行 j_security_check 用户凭据检查?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19729478/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to perform j_security_check user credentials check in Vaadin?
提问by Dmitrii Pisarenko
I have an old web application which I need to migrate to Vaadin.
我有一个旧的 Web 应用程序,需要将其迁移到 Vaadin。
In the old app there is a page which asks the user for login and password.
在旧的应用程序中有一个页面,要求用户输入登录名和密码。
The JSP page looks like this:
JSP 页面如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8"%>
[...]
<head>
<title>Some product</title>
<link rel="stylesheet" type="text/css" href="<%=request.getContextPath()+"/css/styles.css"%>" />
</head>
<body>
<%@ include file="inc/main-navigation.jsp"%>
<form action="j_security_check" method="post" style="margin:0px">
[...]
<input type="text" style="width:100%" name="j_username" />
<input type="password" name="j_password" />
</form>
</body>
</html>
web.xml
contains following entries:
web.xml
包含以下条目:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>Some product</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/login_fail.jsp</form-error-page>
</form-login-config>
</login-config>
This means that in case of unsuccessful authentication the user is directed to page login_fail.jsp
.
这意味着在身份验证失败的情况下,用户将被定向到 page login_fail.jsp
。
In the context.xml
file I found following entry from which I conclude that there is an internal mechanism in Tomcat which reads correct login and password from the specified database and performs their check without any additional code.
在context.xml
文件中,我发现以下条目,从中我得出结论,Tomcat 中有一个内部机制,它从指定的数据库中读取正确的登录名和密码,并在没有任何额外代码的情况下执行它们的检查。
<Context path="/myapp">
<Realm className="org.apache.catalina.realm.JDBCRealm" driverName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
connectionURL="[...]"
userTable="[...]" userNameCol="user_name" userCredCol="user_pass"
userRoleTable="[...]" roleNameCol="role_name"/>
</Context>
In the Vaadin application I have a UI with both text fields and a button.
在 Vaadin 应用程序中,我有一个包含文本字段和按钮的 UI。
public class BookkeepingView extends VerticalLayout implements View {
public BookkeepingView()
{
VerticalLayout contentPanel = new VerticalLayout();
contentPanel.setStyleName("body");
contentPanel.addComponent(getHeaderPanel());
contentPanel.addComponent(getLoginPanel());
contentPanel.addComponent(getFooterPanel());
addComponent(contentPanel);
}
private Component getHeaderPanel() {
return createCustomLayoutPanel("main-navigation");
}
private Component getFooterPanel() {
return createCustomLayoutPanel("copyright");
}
private CustomLayout getLoginPanel() {
Panel panel = new Panel();
panel.setSizeUndefined();
addComponent(panel);
CustomLayout customLayoutPanel = new CustomLayout("login");
final TextField userName = new TextField();
customLayoutPanel.addComponent(userName, "j_username");
final PasswordField password = new PasswordField();
customLayoutPanel.addComponent(password, "j_password");
final Button loginButton = new Button(I18n.l("bookkeeping_login_button"));
customLayoutPanel.addComponent(loginButton, "login");
loginButton.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent clickEvent) {
loginButtonPressed();
}
});
return customLayoutPanel;
}
private void loginButtonPressed() {
Notification.show("Login button pressed", Notification.Type.TRAY_NOTIFICATION);
}
private CustomLayout createCustomLayoutPanel(final String aHtmlFileName) {
Panel panel = new Panel();
panel.setSizeUndefined();
addComponent(panel);
CustomLayout customLayoutPanel = new CustomLayout(aHtmlFileName);
return customLayoutPanel;
}
@Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
}
}
When the user presses the button (method loginButtonPressed
is executed), I want to
当用户按下按钮(方法loginButtonPressed
被执行)时,我想
- check the credentials entered in text fields
userName
andpassword
, - display a notification box, if the credentials are wrong and
- opens another UI (view), if they are correct.
- 您在文本字段中输入的凭据
userName
和password
, - 显示一个通知框,如果凭据错误并且
- 打开另一个 UI(视图),如果它们是正确的。
How can I make my Vaadin application access that Tomcat mechanism for checking the credentials (i. e. my Vaadin application should perform the credentials check in exactly the same way as the old app)?
如何让我的 Vaadin 应用程序访问用于检查凭据的 Tomcat 机制(即,我的 Vaadin 应用程序应该以与旧应用程序完全相同的方式执行凭据检查)?
What code allows me to check whether user name x
and password y
are valid according to database specified in context.xml
?
什么代码允许我根据 中指定的数据库检查用户名x
和密码y
是否有效context.xml
?
Update 1 (05.11.2013):I found a description of how to use realm-based authentication here.
更新1(2013年5月11日):我发现了如何使用基于领域的认证说明这里。
But I ran into a problem:
但是我遇到了一个问题:
The application servlet in the example extends com.vaadin.terminal.gwt.server.AbstractApplicationServlet
, which is not available in my Vaadin 7 project.
示例中的应用程序 servlet extends com.vaadin.terminal.gwt.server.AbstractApplicationServlet
,在我的 Vaadin 7 项目中不可用。
@WebServlet(urlPatterns={"/ui/*", "/VAADIN/*"})
public class DemoAppServlet extends AbstractApplicationServlet {
Update 2 (05.11.2013 15:53):
更新 2 (05.11.2013 15:53):
I tried to implement authentication in the simplest possible way:
我尝试以最简单的方式实现身份验证:
1) Use BASIC authentication mechanism. 2) Configure the web app so that allVaadin pages require the user to be logged in.
1) 使用 BASIC 认证机制。2) 配置 Web 应用程序,以便所有Vaadin 页面都要求用户登录。
In order to achieve this, I added following fragments to web.xml
:
为了实现这一点,我添加了以下片段web.xml
:
<servlet-mapping>
<servlet-name>VaadinDemoApp</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<security-constraint>
<display-name>VaadinDemoApplicationConstraint</display-name>
<web-resource-collection>
<web-resource-name>Vaadin application</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
<role-name>viewer</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Protected page</realm-name>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
<security-role>
<role-name>viewer</role-name>
</security-role>
But it doesn't work: The credentials dialog box is displayed upon access to the application, but when I enter correct credentials and press "OK", the same dialog box appears again.
但它不起作用:访问应用程序时会显示凭据对话框,但是当我输入正确的凭据并按“确定”时,再次出现相同的对话框。
回答by michaldo
I recommend you to exclude authentication from Vaadin. Keep JSP page as authentication form and use default authentication from Servlet specification.
我建议您从 Vaadin 中排除身份验证。保持 JSP 页面作为身份验证形式并使用来自 Servlet 规范的默认身份验证。
If you have programmable authentication in your code, it opens door for bugs. Moreover, your code is more complicated. Better use declarative security. In that case authentication is separated from application. Your application is simpler, security is more trusted.
如果您的代码中具有可编程身份验证,则会为错误打开大门。此外,您的代码更复杂。更好地使用声明式安全性。在这种情况下,身份验证与应用程序分开。您的应用程序更简单,安全性更值得信赖。
Take a look on webinar http://www.youtube.com/watch?v=PNAo3ApWA-AWhole is quite interesting, but example how to make authentication starts from 47 minute. Both solutions are presented: custom code and declarative security.
看看网络研讨会http://www.youtube.com/watch?v=PNAo3ApWA-A整体很有趣,但示例如何从 47 分钟开始进行身份验证。提供了两种解决方案:自定义代码和声明性安全性。
After seeing that webinar I'm sure declarative security is correct choice.
看过那场网络研讨会后,我确信声明式安全是正确的选择。
Declarative security need some adjustment in web.xml. Comparing to pure Vaadin application, not all requests are handled by VaadinServlet: authentication requests must be handled by default. Anyway, declarative security is worth configuration effort.
声明式安全需要在 web.xml 中进行一些调整。与纯 Vaadin 应用程序相比,并非所有请求都由 VaadinServlet 处理:默认情况下必须处理身份验证请求。无论如何,声明式安全是值得的配置努力。
回答by Renat Gilmanov
It seems like you have overcomplicated everything. Please find below real-life solution. It is used for a Vaadin application and simply works.
好像你把一切都复杂化了。请在下面找到现实生活中的解决方案。它用于 Vaadin 应用程序并且可以正常工作。
1. You need external login page
1.您需要外部登录页面
This is the simplest way. If you want, you can easily style that page in order not to break user experience.
这是最简单的方法。如果需要,您可以轻松设置该页面的样式,以免破坏用户体验。
<link rel="stylesheet" type="text/css" href="VAADIN/themes/reindeer/styles.css">
...
<div class="v-app v-theme-reindeer">
As usual you will have the following:
像往常一样,您将拥有以下内容:
<form id="login" method="post" action="j_security_check" >
<input name="j_username" type="text">
<input name="j_password" type="text">
2. I would suggest to have external login failed page
2.我建议有外部登录失败页面
Basically it just needs to notify a user there was something wrong. It might also suggest, for example, to relogin.
基本上它只需要通知用户有问题。例如,它也可能建议重新登录。
3. Configure proper auth method
3.配置正确的认证方法
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/VAADIN/loginPage.html</form-login-page>
<form-error-page>/VAADIN/loginFailed.html</form-error-page>
</form-login-config>
</login-config>
4. Do not forget to set session timeout
4.不要忘记设置会话超时
<session-config>
<session-timeout>60</session-timeout>
</session-config>
5. You are done, just test
5.大功告成,测试