Просмотр исходного кода

jwt token generating on Login, validation to do

mateuszsudra 2 лет назад
Родитель
Сommit
f731bf4ab2
21 измененных файлов с 527 добавлено и 13 удалено
  1. 27 0
      boat-reservation-logic/pom.xml
  2. 21 0
      boat-reservation-logic/src/main/java/pl/sudra/configuration/SecurityConfig.java
  3. 2 0
      boat-reservation-logic/src/main/java/pl/sudra/configuration/SpringConfiguration.java
  4. 30 0
      boat-reservation-logic/src/main/java/pl/sudra/domain/LoginDto.java
  5. 36 0
      boat-reservation-logic/src/main/java/pl/sudra/securityController/CustomExceptionHandler.java
  6. 30 0
      boat-reservation-logic/src/main/java/pl/sudra/securityController/CustomInterceptor.java
  7. 79 0
      boat-reservation-logic/src/main/java/pl/sudra/securityController/JwtRequestFilter.java
  8. 72 0
      boat-reservation-logic/src/main/java/pl/sudra/securityController/JwtTokenUtil.java
  9. 56 5
      boat-reservation-logic/src/main/java/pl/sudra/securityController/SecurityController.java
  10. 32 0
      boat-reservation-logic/src/main/java/pl/sudra/securityController/ValidationErrorResponse.java
  11. 5 0
      boat-reservation-logic/src/main/java/pl/sudra/service/UserService.java
  12. 7 0
      boat-reservation-logic/src/main/java/pl/sudra/service/UserServiceImpl.java
  13. 39 0
      boat-reservation-view/package-lock.json
  14. 3 0
      boat-reservation-view/package.json
  15. 1 1
      boat-reservation-view/src/app/app.module.ts
  16. 66 0
      boat-reservation-view/src/app/auth-service/auth.service.ts
  17. 2 2
      boat-reservation-view/src/app/login-view/login-view.component.html
  18. 9 1
      boat-reservation-view/src/app/login-view/login-view.component.ts
  19. 1 1
      boat-reservation-view/src/app/register-view/register-view.component.html
  20. 8 2
      boat-reservation-view/src/app/register-view/register-view.component.ts
  21. 1 1
      boat-reservation-view/src/app/reservation-view/reservation-view.component.ts

+ 27 - 0
boat-reservation-logic/pom.xml

@@ -137,6 +137,33 @@
             <artifactId>spring-context-support</artifactId>
             <version>6.0.9</version>
         </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-api</artifactId>
+            <version>0.11.2</version>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-impl</artifactId>
+            <version>0.11.2</version>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-jackson</artifactId>
+            <version>0.11.2</version>
+            <scope>runtime</scope>
+        </dependency>
+<!--        &lt;!&ndash; https://mvnrepository.com/artifact/org.springframework.security/spring-security-web &ndash;&gt;-->
+<!--        <dependency>-->
+<!--            <groupId>org.springframework.security</groupId>-->
+<!--            <artifactId>spring-security-web</artifactId>-->
+<!--            <version>6.1.0</version>-->
+<!--        </dependency>-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
 
     </dependencies>
 

+ 21 - 0
boat-reservation-logic/src/main/java/pl/sudra/configuration/SecurityConfig.java

@@ -0,0 +1,21 @@
+package pl.sudra.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.web.SecurityFilterChain;
+
+@Configuration
+@EnableWebSecurity
+public class SecurityConfig {
+
+    @Bean
+    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+        http.authorizeHttpRequests().anyRequest().authenticated();
+        http.formLogin();
+
+        return http.build();
+    }
+
+}

+ 2 - 0
boat-reservation-logic/src/main/java/pl/sudra/configuration/SpringConfiguration.java

@@ -17,6 +17,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 import org.springframework.web.servlet.i18n.CookieLocaleResolver;
 import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
 import org.springframework.web.servlet.view.InternalResourceViewResolver;
+import pl.sudra.securityController.CustomInterceptor;
 
 import java.time.Duration;
 import java.util.Locale;
@@ -57,6 +58,7 @@ public class SpringConfiguration implements WebMvcConfigurer {
         LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
         interceptor.setParamName("lang");
         registry.addInterceptor(interceptor);
+        registry.addInterceptor(new CustomInterceptor());
     }
 
     @Override

+ 30 - 0
boat-reservation-logic/src/main/java/pl/sudra/domain/LoginDto.java

@@ -0,0 +1,30 @@
+package pl.sudra.domain;
+
+public class LoginDto {
+    String username;
+    String password;
+
+    public LoginDto(String username, String password) {
+        this.username = username;
+        this.password = password;
+    }
+
+    public LoginDto() {
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

+ 36 - 0
boat-reservation-logic/src/main/java/pl/sudra/securityController/CustomExceptionHandler.java

@@ -0,0 +1,36 @@
+//package pl.sudra.securityController;
+//
+//import org.springframework.http.HttpHeaders;
+//import org.springframework.http.HttpStatus;
+//import org.springframework.http.ResponseEntity;
+//import org.springframework.web.bind.MethodArgumentNotValidException;
+//import org.springframework.web.bind.annotation.RestControllerAdvice;
+//import org.springframework.web.context.request.WebRequest;
+//import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+//import org.springframework.context.support.DefaultMessageSourceResolvable;
+//
+//
+//import java.util.List;
+//import java.util.stream.Collectors;
+//
+//
+//@RestControllerAdvice
+//public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
+//
+//    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
+//                                                                  HttpHeaders headers,
+//                                                                  HttpStatus status,
+//                                                                  WebRequest request) {
+//        List<String> errors = ex.getBindingResult()
+//                .getAllErrors()
+//                .stream()
+//                .map(DefaultMessageSourceResolvable::getDefaultMessage)
+//                .collect(Collectors.toList());
+//
+//        ValidationErrorResponse errorResponse = new ValidationErrorResponse();
+//        errorResponse.setMessage("Validation Error");
+//        errorResponse.setErrors(errors);
+//
+//        return ResponseEntity.badRequest().body(errorResponse);
+//    }
+//}

+ 30 - 0
boat-reservation-logic/src/main/java/pl/sudra/securityController/CustomInterceptor.java

@@ -0,0 +1,30 @@
+package pl.sudra.securityController;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+public class CustomInterceptor implements HandlerInterceptor {
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        String token = request.getHeader("Authorization");
+        System.out.println("pre");
+        System.out.println(JwtTokenUtil.validateToken(token));
+        return HandlerInterceptor.super.preHandle(request, response, handler);
+    }
+
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+        System.out.println("post");
+        System.out.println(request);
+        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+        System.out.println("after");
+        System.out.println(request);
+        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
+    }
+}

+ 79 - 0
boat-reservation-logic/src/main/java/pl/sudra/securityController/JwtRequestFilter.java

@@ -0,0 +1,79 @@
+//package pl.sudra.securityController;
+//
+//import io.jsonwebtoken.ExpiredJwtException;
+//import jakarta.servlet.FilterChain;
+//import jakarta.servlet.ServletException;
+//import jakarta.servlet.http.HttpServletRequest;
+//import jakarta.servlet.http.HttpServletResponse;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+//import org.springframework.security.core.context.SecurityContextHolder;
+//import org.springframework.security.core.userdetails.UserDetails;
+//import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+//import org.springframework.web.bind.annotation.CrossOrigin;
+//import org.springframework.web.bind.annotation.RestController;
+//import org.springframework.web.filter.OncePerRequestFilter;
+//import pl.sudra.domain.User;
+//import pl.sudra.service.UserService;
+//
+//import java.io.IOException;
+//import java.util.ArrayList;
+//import java.util.List;
+//
+//@RestController
+//@CrossOrigin(origins = "http://localhost:1410")
+//public class JwtRequestFilter extends OncePerRequestFilter {
+//    @Autowired
+//    private UserService userService;
+//
+//    @Autowired
+//    private JwtTokenUtil jwtTokenUtil;
+//
+//    @Override
+//    protected void doFilterInternal(HttpServletRequest request,
+//                                    HttpServletResponse response,
+//                                    FilterChain chain) throws ServletException, IOException {
+//        final String requestTokenHeader = request.getHeader("Authorization");
+//        System.out.println("Im doing something");
+//        String username = null;
+//        String jwtToken = null;// JWT Token is in the form "Bearer token". Remove Bearer word and get only the Token
+//
+//        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
+//            jwtToken = requestTokenHeader.substring(7);
+//            try {
+//                username = jwtTokenUtil.getUsernameFromToken(jwtToken);
+//            } catch (IllegalArgumentException e) {
+//                System.out.println("Unable to get JWT Token");
+//            } catch (ExpiredJwtException e) {
+//                System.out.println("JWT Token has expired");
+//            }
+//        } else {
+//            logger.warn("JWT Token does not begin with Bearer String");
+//        }
+//
+//        //Once we get the token validate it.
+//        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
+//
+//            User user = this.userService.findByUsername(username).get();
+//
+//            // if token is valid configure Spring Security to manually set authentication
+//            if (jwtTokenUtil.validateToken(jwtToken, user)) {
+//
+////                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
+////                        new UsernamePasswordAuthenticationToken(user,
+////                                null, user.getRole());
+//
+//                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
+//                        new UsernamePasswordAuthenticationToken(user,
+//                                null, List.of());
+//                usernamePasswordAuthenticationToken
+//                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+//                // After setting the Authentication in the context, we specify
+//                // that the current user is authenticated. So it passes the Spring Security Configurations successfully.
+//                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
+//            }
+//        }
+//        chain.doFilter(request, response);
+//    }
+//
+//}

+ 72 - 0
boat-reservation-logic/src/main/java/pl/sudra/securityController/JwtTokenUtil.java

@@ -0,0 +1,72 @@
+package pl.sudra.securityController;
+
+import com.sun.jdi.event.ExceptionEvent;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import org.springframework.stereotype.Component;
+import pl.sudra.domain.User;
+
+import java.util.Date;
+import java.util.function.Function;
+
+@Component
+public class JwtTokenUtil {
+
+    private static final String SECRET_KEY = "SuperSecureKey2023".repeat(5); // Replace with your own secret key
+    //    private static final long EXPIRATION_TIME = 86400000; // 24 hours in milliseconds
+    private static final long EXPIRATION_TIME = 1000 * 30; // 30 sec
+
+    public static String generateToken(String username, Long id, String role) {
+        Date now = new Date();
+        Date expiration = new Date(now.getTime() + EXPIRATION_TIME);
+
+        Claims claims = Jwts.claims();
+
+        claims.put("sub", username);
+        claims.put("sub_id", String.valueOf(id));
+        claims.put("sub_role", role);
+        claims.put("iat", now);
+        claims.put("exp", expiration);
+
+        return Jwts.builder()
+                .setClaims(claims)
+                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
+                .compact();
+    }
+
+    public static boolean validateToken(String token) {
+//        final String username = this.getUsernameFromToken(token);
+//        return (username.equals(user.getUsername()) && !isTokenExpired(token));
+        try {
+            Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    private Boolean isTokenExpired(String token) {
+        final Date expiration = getExpirationDateFromToken(token);
+        return expiration.before(new Date());
+    }
+
+
+    public String getUsernameFromToken(String token) {
+        return getClaimFromToken(token, Claims::getSubject);
+    }
+
+
+    public Date getExpirationDateFromToken(String token) {
+        return getClaimFromToken(token, Claims::getExpiration);
+    }
+
+    public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
+        final Claims claims = getAllClaimsFromToken(token);
+        return claimsResolver.apply(claims);
+    }
+
+    private Claims getAllClaimsFromToken(String token) {
+        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
+    }
+}

+ 56 - 5
boat-reservation-logic/src/main/java/pl/sudra/securityController/SecurityController.java

@@ -3,18 +3,21 @@ package pl.sudra.securityController;
 
 import jakarta.validation.Valid;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.validation.BindingResult;
 import org.springframework.web.bind.annotation.*;
+import pl.sudra.domain.LoginDto;
 import pl.sudra.domain.User;
 import pl.sudra.service.UserService;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import java.util.stream.Collectors;
-//import pl.sudra.configuration.SpringConfiguration.PasswordEncoder;
+
 import org.springframework.context.support.DefaultMessageSourceResolvable;
 
 @RestController
@@ -33,6 +36,7 @@ public class SecurityController {
             method = RequestMethod.POST,
             produces = MediaType.APPLICATION_JSON_VALUE)
     public ResponseEntity<?> Register(@Valid @RequestBody User user, BindingResult bindingResult) {
+        // validation check
         if (bindingResult.hasErrors()) {
             List<String> errors = bindingResult.getAllErrors()
                     .stream()
@@ -45,7 +49,7 @@ public class SecurityController {
 
             return ResponseEntity.badRequest().body(errorResponse);
         }
-
+        // duplication check
         boolean isUsernameNotUnique = this.userService.isUsernameNotUnique(user.getUsername());
         boolean isEmailNotUnique = this.userService.isEmailNotUnique(user.getEmail());
 
@@ -53,8 +57,8 @@ public class SecurityController {
             ValidationErrorResponse errorResponse = new ValidationErrorResponse();
             errorResponse.setMessage("Duplication Error");
             List<String> errors = new ArrayList<>();
-            if(isUsernameNotUnique) errors.add("Username already exist in database.");
-            if(isEmailNotUnique) errors.add("Email already exist in database.");
+            if (isUsernameNotUnique) errors.add("Username already exist in database.");
+            if (isEmailNotUnique) errors.add("Email already exist in database.");
             errorResponse.setErrors(errors);
 
             return ResponseEntity.badRequest().body(errorResponse);
@@ -66,7 +70,54 @@ public class SecurityController {
 
         this.userService.registerUser(user);
 
-        return ResponseEntity.ok("Request is valid");
+        return ResponseEntity
+                .status(HttpStatus.OK)
+                .body("{\"message\": \"Request is valid\"}");
     }
 
+    @RequestMapping(
+            value = "/login",
+            method = RequestMethod.POST,
+            produces = MediaType.APPLICATION_JSON_VALUE)
+    public ResponseEntity<?> Login(@Valid @RequestBody LoginDto loginDto) {
+        Optional<User> user = this.userService.findByUsername(loginDto.getUsername());
+        if (user.isEmpty()) {
+            ValidationErrorResponse errorResponse = new ValidationErrorResponse();
+            errorResponse.setMessage("Login Error");
+            List<String> errors = new ArrayList<>();
+            errors.add("No such username in database.");
+            errorResponse.setErrors(errors);
+
+            return ResponseEntity.badRequest().body(errorResponse);
+        } else {
+            if (passwordEncoder.matches(loginDto.getPassword(), user.get().getPassword())) {
+                System.out.println("Login successful");
+                String jwtToken = JwtTokenUtil.generateToken(
+                        user.get().getUsername(),
+                        user.get().getId(),
+                        user.get().getRole()
+                );
+                System.out.println(jwtToken);
+
+//                return ResponseEntity.ok()
+//                        .header("Authorization", "Bearer " + jwtToken)
+//                        .body("Request is valid");
+
+                return ResponseEntity
+                        .status(HttpStatus.OK)
+                        .header("Authorization", "Bearer " + jwtToken)
+                        .body("{\"message\": \"Request is valid\"," +
+                                "\"Authorization\": \"Bearer " + jwtToken + "\"}");
+            } else {
+                ValidationErrorResponse errorResponse = new ValidationErrorResponse();
+                errorResponse.setMessage("Login Error");
+                List<String> errors = new ArrayList<>();
+                errors.add("Password is not matching.");
+                errorResponse.setErrors(errors);
+
+                return ResponseEntity.badRequest().body(errorResponse);
+            }
+
+        }
+    }
 }

+ 32 - 0
boat-reservation-logic/src/main/java/pl/sudra/securityController/ValidationErrorResponse.java

@@ -0,0 +1,32 @@
+package pl.sudra.securityController;
+
+import java.util.List;
+
+public class ValidationErrorResponse {
+    private String message;
+    private List<String> errors;
+
+    public ValidationErrorResponse() {
+    }
+
+    public ValidationErrorResponse(String message, List<String> errors) {
+        this.message = message;
+        this.errors = errors;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public List<String> getErrors() {
+        return errors;
+    }
+
+    public void setErrors(List<String> errors) {
+        this.errors = errors;
+    }
+}

+ 5 - 0
boat-reservation-logic/src/main/java/pl/sudra/service/UserService.java

@@ -2,9 +2,14 @@ package pl.sudra.service;
 
 import pl.sudra.domain.User;
 
+import java.util.Optional;
+
 public interface UserService {
     void registerUser(User user);
 
     boolean isEmailNotUnique(String email);
+
     boolean isUsernameNotUnique(String username);
+
+    Optional<User> findByUsername(String username);
 }

+ 7 - 0
boat-reservation-logic/src/main/java/pl/sudra/service/UserServiceImpl.java

@@ -5,6 +5,8 @@ import org.springframework.transaction.annotation.Transactional;
 import pl.sudra.domain.User;
 import pl.sudra.repository.UserRepository;
 
+import java.util.Optional;
+
 @Service("userService")
 @Transactional
 public class UserServiceImpl implements UserService {
@@ -28,4 +30,9 @@ public class UserServiceImpl implements UserService {
     public boolean isUsernameNotUnique(String username) {
         return this.userRepository.findByUsername(username).isPresent();
     }
+
+    @Override
+    public Optional<User> findByUsername(String username) {
+        return this.userRepository.findByUsername(username);
+    }
 }

+ 39 - 0
boat-reservation-view/package-lock.json

@@ -16,6 +16,9 @@
         "@angular/platform-browser": "^16.0.0",
         "@angular/platform-browser-dynamic": "^16.0.0",
         "@angular/router": "^16.0.0",
+        "@auth0/angular-jwt": "^5.1.2",
+        "jwt-decode": "^3.1.2",
+        "node": "^20.2.0",
         "rxjs": "~7.8.0",
         "tslib": "^2.3.0",
         "zone.js": "~0.13.0"
@@ -552,6 +555,17 @@
       "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==",
       "dev": true
     },
+    "node_modules/@auth0/angular-jwt": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/@auth0/angular-jwt/-/angular-jwt-5.1.2.tgz",
+      "integrity": "sha512-8ulz24cPpEkZb9/AdAaWfYIkomQDbZqvB9LproF/48Klnr30EJx09AYF9sbKTN4qLSgIZSlCb/Y7XQJZ51vSzA==",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "peerDependencies": {
+        "@angular/common": ">=12.0.0"
+      }
+    },
     "node_modules/@babel/code-frame": {
       "version": "7.21.4",
       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
@@ -7076,6 +7090,11 @@
         "node >= 0.2.0"
       ]
     },
+    "node_modules/jwt-decode": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz",
+      "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="
+    },
     "node_modules/karma": {
       "version": "6.4.2",
       "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.2.tgz",
@@ -8304,6 +8323,21 @@
         "node-gyp-build": "^4.2.2"
       }
     },
+    "node_modules/node": {
+      "version": "20.2.0",
+      "resolved": "https://registry.npmjs.org/node/-/node-20.2.0.tgz",
+      "integrity": "sha512-oF1+u42FT/nFtRFdcsUNdexVCWQKAHB7LtKHOk/9o0cQBq19leB/0awrB3ZdzHU/Pz9tC9RHwgd52PK9bON30A==",
+      "hasInstallScript": true,
+      "dependencies": {
+        "node-bin-setup": "^1.0.0"
+      },
+      "bin": {
+        "node": "bin/node"
+      },
+      "engines": {
+        "npm": ">=5.0.0"
+      }
+    },
     "node_modules/node-addon-api": {
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
@@ -8311,6 +8345,11 @@
       "dev": true,
       "optional": true
     },
+    "node_modules/node-bin-setup": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.1.3.tgz",
+      "integrity": "sha512-opgw9iSCAzT2+6wJOETCpeRYAQxSopqQ2z+N6BXwIMsQQ7Zj5M8MaafQY8JMlolRR6R1UXg2WmhKp0p9lSOivg=="
+    },
     "node_modules/node-forge": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",

+ 3 - 0
boat-reservation-view/package.json

@@ -20,6 +20,9 @@
     "@angular/platform-browser": "^16.0.0",
     "@angular/platform-browser-dynamic": "^16.0.0",
     "@angular/router": "^16.0.0",
+    "@auth0/angular-jwt": "^5.1.2",
+    "jwt-decode": "^3.1.2",
+    "node": "^20.2.0",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",
     "zone.js": "~0.13.0"

+ 1 - 1
boat-reservation-view/src/app/app.module.ts

@@ -1,4 +1,4 @@
-import {APP_INITIALIZER, NgModule} from '@angular/core';
+import {APP_INITIALIZER, InjectionToken, NgModule} from '@angular/core';
 import {BrowserModule} from '@angular/platform-browser';
 
 import {RouterModule} from '@angular/router';

+ 66 - 0
boat-reservation-view/src/app/auth-service/auth.service.ts

@@ -0,0 +1,66 @@
+import {Injectable} from '@angular/core';
+import {HttpClient, HttpHeaders} from "@angular/common/http";
+// import {JwtHelperService, JWT_OPTIONS} from "@auth0/angular-jwt";
+import jwt_decode from 'jwt-decode';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class AuthService {
+  constructor(private http: HttpClient
+  ) {
+  }
+
+  login(username: string, password: string) {
+    console.log("login")
+    const url = 'http://localhost:2137/login';
+    let loginDto = {
+      "username": username,
+      "password": password
+    }
+    const headers = new HttpHeaders()
+      .set('Content-Type', 'application/json');
+
+    interface Token {
+      "exp": number,
+      "iat": number,
+      "sub": string,
+      "sub_id": string,
+      "sub_role": string
+    }
+
+    this.http.post<any>(url, loginDto, {headers}).subscribe(
+      (response) => {
+        sessionStorage.setItem('jwtToken', response.Authorization)
+
+        let decoded = jwt_decode<Token>(response.Authorization)
+
+        sessionStorage.setItem('username', decoded.sub)
+        sessionStorage.setItem('username_id', decoded.sub_id)
+        sessionStorage.setItem('role', decoded.sub_role)
+      },
+      (error) => {
+        console.error('Error making POST request:', error);
+      });
+  }
+
+  register(username: string, password: string, email: string) {
+    console.log("register")
+    const url = 'http://localhost:2137/register';
+    let registerDto = {
+      "username": username,
+      "password": password,
+      "email": email
+    }
+    const headers = new HttpHeaders()
+      .set('Content-Type', 'application/json');
+
+    this.http.post(url, registerDto, {headers}).subscribe(
+      (response) => {
+        console.log('POST request successful', response);
+      },
+      (error) => {
+        console.error('Error making POST request:', error);
+      });
+  }
+}

+ 2 - 2
boat-reservation-view/src/app/login-view/login-view.component.html

@@ -6,7 +6,7 @@
     <label for="username" style="text-align: left;">Username:</label>
     <input type="text"
            id="username"
-           name="name" [(ngModel)]="formData.name" required>
+           name="name" [(ngModel)]="formData.username" required>
 
     <label for="password" style="text-align: left;">Password:</label>
     <input type="text"
@@ -16,7 +16,7 @@
     <input type="submit" value="Login">
   </form>
   <br>
-  <p> Don't have an account?</p>
+  <p>Don't have an account?</p>
   <input type="submit" value="REGISTER HERE" routerLink="/register" routerLinkActive="activebutton">
   <br><br>
 </div>

+ 9 - 1
boat-reservation-view/src/app/login-view/login-view.component.ts

@@ -1,4 +1,5 @@
-import { Component } from '@angular/core';
+import {Component} from '@angular/core';
+import {AuthService} from "../auth-service/auth.service";
 
 @Component({
   selector: 'app-login-view',
@@ -8,7 +9,14 @@ import { Component } from '@angular/core';
 export class LoginViewComponent {
   formData: any = {};
 
+  constructor(private authService: AuthService) {
+  }
+
   login() {
     console.log("login attempt")
+    console.log(this.formData)
+    this.authService.login(
+      this.formData.username,
+      this.formData.password)
   }
 }

+ 1 - 1
boat-reservation-view/src/app/register-view/register-view.component.html

@@ -5,7 +5,7 @@
   <label for="username">Username:</label>
   <input type="text"
          id="username"
-         name="name" [(ngModel)]="formData.name" required>
+         name="name" [(ngModel)]="formData.username" required>
 
   <label for="password">Password:</label>
   <input type="text"

+ 8 - 2
boat-reservation-view/src/app/register-view/register-view.component.ts

@@ -1,4 +1,6 @@
 import {Component} from '@angular/core';
+import {BoatsService} from "../boats-service/boats.service";
+import {AuthService} from "../auth-service/auth.service";
 
 @Component({
   selector: 'app-register-view',
@@ -8,11 +10,15 @@ import {Component} from '@angular/core';
 export class RegisterViewComponent {
   formData: any = {};
 
-  constructor() {
+  constructor(private authService: AuthService) {
   }
 
   registerUser() {
     console.log("register attempt")
-
+    console.log(this.formData)
+    this.authService.register(
+      this.formData.username,
+      this.formData.password,
+      this.formData.email)
   }
 }

+ 1 - 1
boat-reservation-view/src/app/reservation-view/reservation-view.component.ts

@@ -53,7 +53,7 @@ export class ReservationViewComponent {
   }
 
   isItTooLateToStart() {
-    return this.fromHour <= new Date().getHours() + 1
+    return this.fromHour <= new Date().getHours()
   }
 
   isFormNotValid(){