Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

LoginForm.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.ui;
  17. import java.io.ByteArrayInputStream;
  18. import java.io.InputStream;
  19. import java.io.Serializable;
  20. import java.lang.reflect.Method;
  21. import java.nio.charset.StandardCharsets;
  22. import java.util.HashMap;
  23. import java.util.Map;
  24. import com.vaadin.server.StreamResource;
  25. import com.vaadin.shared.ApplicationConstants;
  26. import com.vaadin.shared.Registration;
  27. import com.vaadin.shared.ui.loginform.LoginFormConstants;
  28. import com.vaadin.shared.ui.loginform.LoginFormRpc;
  29. import com.vaadin.shared.ui.loginform.LoginFormState;
  30. import com.vaadin.util.ReflectTools;
  31. /**
  32. * Login form with auto-completion and auto-fill for all major browsers. You can
  33. * derive from this class and implement the
  34. * {@link #createContent(com.vaadin.ui.TextField, com.vaadin.ui.PasswordField, com.vaadin.ui.Button)}
  35. * method to build the layout using the text fields and login button that are
  36. * passed to that method. The supplied components are specially treated so that
  37. * they work with password managers.
  38. * <p>
  39. * To customize the fields or to replace them with your own implementations, you
  40. * can override {@link #createUsernameField()}, {@link #createPasswordField()}
  41. * and {@link #createLoginButton()}. These methods are called automatically and
  42. * cannot be called by your code. Captions can be reset by overriding
  43. * {@link #getUsernameCaption()}, {@link #getPasswordCaption()} and
  44. * {@link #getLoginButtonCaption()}.
  45. * <p>
  46. * Note that the API of LoginForm changed significantly in Vaadin 7.7.
  47. *
  48. * @since 5.3
  49. */
  50. public class LoginForm extends AbstractSingleComponentContainer {
  51. /**
  52. * Event sent when the login form is submitted.
  53. */
  54. public static class LoginEvent extends Component.Event {
  55. private final Map<String, String> params;
  56. /**
  57. * Creates a login event using the given source and the given
  58. * parameters.
  59. *
  60. * @param source
  61. * the source of the event
  62. * @param params
  63. */
  64. private LoginEvent(LoginForm source, Map<String, String> params) {
  65. super(source);
  66. this.params = params;
  67. }
  68. @Override
  69. public LoginForm getSource() {
  70. return (LoginForm) super.getSource();
  71. }
  72. /**
  73. * Gets the login parameter with the given name.
  74. *
  75. * @param name
  76. * the name of the parameter
  77. * @return the value of the parameter or null if no such parameter is
  78. * present
  79. */
  80. public String getLoginParameter(String name) {
  81. return params.get(name);
  82. }
  83. }
  84. /**
  85. * Listener triggered when a login occurs in a {@link LoginForm}.
  86. */
  87. @FunctionalInterface
  88. public interface LoginListener extends Serializable {
  89. /**
  90. * Event method invoked when the login button is pressed in a login
  91. * form.
  92. *
  93. * @param event
  94. * the login event
  95. */
  96. public void onLogin(LoginEvent event);
  97. }
  98. /**
  99. * Internal stream source for the login URL - always returns "Success" and
  100. * ignores the values received.
  101. */
  102. private static class LoginStreamSource
  103. implements StreamResource.StreamSource {
  104. @Override
  105. public InputStream getStream() {
  106. return new ByteArrayInputStream(
  107. "<html>Success</html>".getBytes(StandardCharsets.UTF_8));
  108. }
  109. }
  110. private static final Method ON_LOGIN_METHOD = ReflectTools
  111. .findMethod(LoginListener.class, "onLogin", LoginEvent.class);
  112. private boolean initialized;
  113. private String usernameCaption = "Username";
  114. private String passwordCaption = "Password";
  115. private String loginButtonCaption = "Login";
  116. /**
  117. * Customize the user name field. Only for overriding, do not call.
  118. *
  119. * @return the user name field
  120. * @since 7.7
  121. */
  122. protected TextField createUsernameField() {
  123. throwIfInitialized();
  124. TextField field = new TextField(getUsernameCaption());
  125. field.focus();
  126. return field;
  127. }
  128. /**
  129. * Gets the caption set with {@link #setUsernameCaption(String)}. Note that
  130. * this method might not match what is shown to the user if
  131. * {@link #createUsernameField()} has been overridden.
  132. *
  133. * @return the user name field caption
  134. */
  135. public String getUsernameCaption() {
  136. return usernameCaption;
  137. }
  138. /**
  139. * Sets the caption of the user name field. Note that the caption can only
  140. * be set with this method before the login form has been initialized
  141. * (attached).
  142. * <p>
  143. * As an alternative to calling this method, the method
  144. * {@link #createUsernameField()} can be overridden.
  145. *
  146. * @param usernameCaption
  147. * the caption to set for the user name field
  148. */
  149. public void setUsernameCaption(String usernameCaption) {
  150. this.usernameCaption = usernameCaption;
  151. }
  152. /**
  153. * Customize the password field. Only for overriding, do not call.
  154. *
  155. * @return the password field
  156. * @since 7.7
  157. */
  158. protected PasswordField createPasswordField() {
  159. throwIfInitialized();
  160. return new PasswordField(getPasswordCaption());
  161. }
  162. /**
  163. * Gets the caption set with {@link #setPasswordCaption(String)}. Note that
  164. * this method might not match what is shown to the user if
  165. * {@link #createPasswordField()} has been overridden.
  166. *
  167. *
  168. * @return the password field caption
  169. */
  170. public String getPasswordCaption() {
  171. return passwordCaption;
  172. }
  173. /**
  174. * Set the caption of the password field. Note that the caption can only be
  175. * set with this method before the login form has been initialized
  176. * (attached).
  177. * <p>
  178. * As an alternative to calling this method, the method
  179. * {@link #createPasswordField()} can be overridden.
  180. *
  181. * @param passwordCaption
  182. * the caption for the password field
  183. */
  184. public void setPasswordCaption(String passwordCaption) {
  185. this.passwordCaption = passwordCaption;
  186. }
  187. /**
  188. * Customize the login button. Only for overriding, do not call.
  189. *
  190. * @return the login button
  191. * @since 7.7
  192. */
  193. protected Button createLoginButton() {
  194. throwIfInitialized();
  195. return new Button(getLoginButtonCaption());
  196. }
  197. /**
  198. * Gets the caption set with {@link #setLoginButtonCaption(String)}. Note
  199. * that this method might not match what is shown to the user if
  200. * {@link #createLoginButton()} has been overridden.
  201. *
  202. * @return the login button caption
  203. */
  204. public String getLoginButtonCaption() {
  205. return loginButtonCaption;
  206. }
  207. /**
  208. * Sets the caption of the login button. Note that the caption can only be
  209. * set with this method before the login form has been initialized
  210. * (attached).
  211. * <p>
  212. * As an alternative to calling this method, the method
  213. * {@link #createLoginButton()} can be overridden.
  214. *
  215. * @param loginButtonCaption
  216. * new caption
  217. */
  218. public void setLoginButtonCaption(String loginButtonCaption) {
  219. this.loginButtonCaption = loginButtonCaption;
  220. }
  221. @Override
  222. protected LoginFormState getState() {
  223. return (LoginFormState) super.getState();
  224. }
  225. @Override
  226. protected LoginFormState getState(boolean markAsDirty) {
  227. return (LoginFormState) super.getState(markAsDirty);
  228. }
  229. @Override
  230. public void attach() {
  231. super.attach();
  232. init();
  233. }
  234. private void throwIfInitialized() {
  235. if (initialized) {
  236. throw new IllegalStateException(
  237. "Already initialized. The create methods may not be called explicitly.");
  238. }
  239. }
  240. /**
  241. * Create the content for the login form with the supplied user name field,
  242. * password field and the login button. You cannot use any other text fields
  243. * or buttons for this purpose. To replace these components with your own
  244. * implementations, override {@link #createUsernameField()},
  245. * {@link #createPasswordField()} and {@link #createLoginButton()}. If you
  246. * only want to change the default captions, override
  247. * {@link #getUsernameCaption()}, {@link #getPasswordCaption()} and
  248. * {@link #getLoginButtonCaption()}. You do not have to use the login button
  249. * in your layout.
  250. *
  251. * @param userNameField
  252. * the user name text field
  253. * @param passwordField
  254. * the password field
  255. * @param loginButton
  256. * the login button
  257. * @return content component
  258. * @since 7.7
  259. */
  260. protected Component createContent(TextField userNameField,
  261. PasswordField passwordField, Button loginButton) {
  262. VerticalLayout layout = new VerticalLayout();
  263. layout.setSpacing(true);
  264. layout.setMargin(true);
  265. layout.addComponent(userNameField);
  266. layout.addComponent(passwordField);
  267. layout.addComponent(loginButton);
  268. return layout;
  269. }
  270. private void init() {
  271. if (initialized) {
  272. return;
  273. }
  274. LoginFormState state = getState();
  275. state.userNameFieldConnector = createUsernameField();
  276. state.passwordFieldConnector = createPasswordField();
  277. state.loginButtonConnector = createLoginButton();
  278. StreamResource resource = new StreamResource(new LoginStreamSource(),
  279. LoginFormConstants.LOGIN_RESOURCE_NAME);
  280. resource.setMIMEType(ApplicationConstants.CONTENT_TYPE_TEXT_HTML_UTF_8);
  281. resource.setCacheTime(-1);
  282. setResource(LoginFormConstants.LOGIN_RESOURCE_NAME, resource);
  283. registerRpc((LoginFormRpc) this::login);
  284. initialized = true;
  285. setContent(createContent(getUsernameField(), getPasswordField(),
  286. getLoginButton()));
  287. }
  288. private TextField getUsernameField() {
  289. assert initialized;
  290. return (TextField) getState(false).userNameFieldConnector;
  291. }
  292. private PasswordField getPasswordField() {
  293. assert initialized;
  294. return (PasswordField) getState(false).passwordFieldConnector;
  295. }
  296. private Button getLoginButton() {
  297. assert initialized;
  298. return (Button) getState(false).loginButtonConnector;
  299. }
  300. /**
  301. * Handles the login.
  302. * <p>
  303. * In deferred mode, this method is called after the dummy POST request that
  304. * triggers the password manager has been completed. In direct mode (the
  305. * default setting), it is called directly when the user hits the enter key
  306. * or clicks on the login button. In the latter case, you cannot change the
  307. * URL in the method or the password manager will not be triggered.
  308. */
  309. private void login() {
  310. HashMap<String, String> params = new HashMap<>();
  311. params.put("username", getUsernameField().getValue());
  312. params.put("password", getPasswordField().getValue());
  313. LoginEvent event = new LoginEvent(LoginForm.this, params);
  314. fireEvent(event);
  315. }
  316. /**
  317. * Adds a {@link LoginListener}.
  318. * <p>
  319. * The listener is called when the user presses the login button.
  320. *
  321. * @param listener
  322. * the listener to add
  323. * @return a registration object for removing the listener
  324. * @since 8.0
  325. */
  326. public Registration addLoginListener(LoginListener listener) {
  327. return addListener(LoginEvent.class, listener, ON_LOGIN_METHOD);
  328. }
  329. /**
  330. * Removes a {@link LoginListener}.
  331. *
  332. * @param listener
  333. * the listener to remove
  334. * @deprecated As of 8.0, replaced by {@link Registration#remove()} in the
  335. * registration object returned from
  336. * {@link #addLoginListener(LoginListener)}.
  337. */
  338. @Deprecated
  339. public void removeLoginListener(LoginListener listener) {
  340. removeListener(LoginEvent.class, listener, ON_LOGIN_METHOD);
  341. }
  342. }