diff --git a/build.gradle b/build.gradle
index 4e0e9cb..b00646e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -120,6 +120,10 @@ dependencies {
compile group: 'org.webjars', name: 'jquery', version: '3.3.1-1'
compile group: 'org.webjars.npm', name: 'jquery.easing', version: '1.4.1'
compile group: 'org.webjars', name: 'font-awesome', version: '4.7.0'
+ compile group: 'org.webjars.npm', name: 'react', version: '16.7.0'
+ compile group: 'org.webjars.npm', name: 'react-dom', version: '16.7.0'
+ compile group: 'org.webjars.npm', name: 'material-ui__core', version: '3.5.1'
+ compile group: 'org.webjars.npm', name: 'babel-standalone', version: '6.26.0'
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.5.0'
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.5.0'
diff --git a/src/main/java/ru/ulstu/configuration/Constants.java b/src/main/java/ru/ulstu/configuration/Constants.java
index 0a2268a..fb3809c 100644
--- a/src/main/java/ru/ulstu/configuration/Constants.java
+++ b/src/main/java/ru/ulstu/configuration/Constants.java
@@ -10,7 +10,7 @@ public class Constants {
public static final String LOGIN_REGEX = "^[_'.@A-Za-z0-9-]*$";
public static final String COOKIES_NAME = "JSESSIONID";
- public static final String LOGOUT_URL = "/login?logout";
+ public static final String LOGOUT_URL = "/login";
public static final String SESSION_ID_ATTR = "sessionId";
public static final int SESSION_TIMEOUT_SECONDS = 30 * 60;
diff --git a/src/main/java/ru/ulstu/configuration/SecurityConfiguration.java b/src/main/java/ru/ulstu/configuration/SecurityConfiguration.java
index da498fa..dc97ee4 100644
--- a/src/main/java/ru/ulstu/configuration/SecurityConfiguration.java
+++ b/src/main/java/ru/ulstu/configuration/SecurityConfiguration.java
@@ -13,6 +13,7 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import ru.ulstu.user.controller.UserController;
@@ -33,17 +34,20 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final UserService userService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final AuthenticationSuccessHandler authenticationSuccessHandler;
+ private final AuthenticationFailureHandler authenticationFailureHandler;
private final LogoutSuccessHandler logoutSuccessHandler;
private final ApplicationProperties applicationProperties;
public SecurityConfiguration(UserService userService,
BCryptPasswordEncoder bCryptPasswordEncoder,
AuthenticationSuccessHandler authenticationSuccessHandler,
+ AuthenticationFailureHandler authenticationFailureHandler,
LogoutSuccessHandler logoutSuccessHandler,
ApplicationProperties applicationProperties) {
this.userService = userService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
this.authenticationSuccessHandler = authenticationSuccessHandler;
+ this.authenticationFailureHandler = authenticationFailureHandler;
this.logoutSuccessHandler = logoutSuccessHandler;
this.applicationProperties = applicationProperties;
}
@@ -75,6 +79,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.and()
.formLogin()
.loginPage("/login")
+ .failureHandler(authenticationFailureHandler)
.successHandler(authenticationSuccessHandler)
.permitAll()
.and()
diff --git a/src/main/java/ru/ulstu/user/component/UserSessionLoginFailureHandler.java b/src/main/java/ru/ulstu/user/component/UserSessionLoginFailureHandler.java
new file mode 100644
index 0000000..12e1670
--- /dev/null
+++ b/src/main/java/ru/ulstu/user/component/UserSessionLoginFailureHandler.java
@@ -0,0 +1,34 @@
+package ru.ulstu.user.component;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Calendar;
+import java.util.HashMap;
+
+@Component
+public class UserSessionLoginFailureHandler implements AuthenticationFailureHandler {
+
+ private ObjectMapper objectMapper = new ObjectMapper();
+
+ @Override
+ public void onAuthenticationFailure(
+ HttpServletRequest request,
+ HttpServletResponse response,
+ AuthenticationException exception)
+ throws IOException, ServletException {
+
+ response.setStatus(HttpStatus.UNAUTHORIZED.value());
+ response.getOutputStream()
+ .write("Не удается войти.
Пожалуйста, проверьте правильность написания логина и пароля.".getBytes(StandardCharsets.UTF_8));
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index fb1b116..7603c2c 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -34,5 +34,5 @@ liquibase.change-log=classpath:db/changelog-master.xml
# Application Settings
ng-tracker.base-url=http://127.0.0.1:8080
ng-tracker.undead-user-login=admin
-ng-tracker.dev-mode=true
+ng-tracker.dev-mode=false
ng-tracker.use-https=false
\ No newline at end of file
diff --git a/src/main/resources/public/js/react/loginPage/components/login.js b/src/main/resources/public/js/react/loginPage/components/login.js
new file mode 100644
index 0000000..db3f96f
--- /dev/null
+++ b/src/main/resources/public/js/react/loginPage/components/login.js
@@ -0,0 +1,100 @@
+const {
+ Card,
+ CardHeader,
+ CardContent,
+ FormControl,
+ FormLabel,
+ TextField,
+ Button
+} = window['material-ui'];
+
+class LoginForm extends React.Component{
+ state = {
+ isValidUsername: false,
+ isValidPassword: false,
+ username: "",
+ password: "",
+ errorsMessage: ""
+ };
+
+ handleChangeUsername = event => {
+ this.setState({
+ username: event.target.value,
+ isValidUsername: /^[_'.@A-Za-z0-9-]*$/.test(event.target.value)
+ });
+ };
+
+ handleChangePassword = event => {
+ this.setState({
+ password: event.target.value,
+ isValidPassword: (event.target.value.length > 4)
+ });
+ };
+
+ handleSubmit = loginForm => () => {
+ if (loginForm.state.isValidUsername && loginForm.state.isValidPassword){
+ $.post(
+ "/login",
+ loginForm.state,
+ this.handleResponseAjaxPost(loginForm)("success")
+ ).fail(this.handleResponseAjaxPost(loginForm)("error"));
+ }
+ };
+
+ handleResponseAjaxPost = loginForm => status => response => {
+ if (status === "success"){
+ window.location.href = "/index";
+ loginForm.setState({
+ errorsMessage: ""
+ });
+ } else if (status === "error"){
+ loginForm.setState({
+ errorsMessage: response.responseText,
+ password: "",
+ isValidPassword: false
+ })
+ }
+ };
+
+ render(){
+ return (
+