Procházet zdrojové kódy

RIFFMASTER: BACKEND: songs correctly fetched after login with token

Kuba před 2 roky
rodič
revize
99668981a2
24 změnil soubory, kde provedl 203 přidání a 24050 odebrání
  1. 1 24021
      Backend/Spring/.idea/workspace.xml
  2. 1 19
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.java
  3. 7 0
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/configuration/SpringConfiguration.java
  4. 157 0
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/security/CustomInterceptor.java
  5. 28 7
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/security/JwtTokenUtil.java
  6. binární
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.class
  7. binární
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/configuration/SpringConfiguration.class
  8. binární
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/security/CustomInterceptor.class
  9. binární
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/security/JwtTokenUtil.class
  10. binární
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.class
  11. binární
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/configuration/SpringConfiguration.class
  12. binární
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/security/CustomInterceptor.class
  13. binární
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/security/JwtTokenUtil.class
  14. binární
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/12.pack
  15. binární
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/17.pack
  16. binární
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/2.pack
  17. binární
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/7.pack
  18. binární
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/8.pack
  19. binární
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack
  20. binární
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack.old
  21. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/287cf156bc7a9c92e86ba699635233092fa675ca3f3c2622e456a3a0172ce17d.json
  22. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/405365a0d40ce49e4002a4bce7027e4038affd582987e7aa218eece675e9eb41.json
  23. 4 2
      Frontend/RiffMasterFront/.idea/workspace.xml
  24. 5 1
      Frontend/RiffMasterFront/src/app/Services/song.service.ts

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 24021
Backend/Spring/.idea/workspace.xml


+ 1 - 19
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.java

@@ -79,29 +79,15 @@ public class SecurityConfiguration {
 
         http.cors().and().csrf().disable()
                 .authorizeHttpRequests((authz) -> authz
-                        .requestMatchers("/riffmaster/login*").permitAll()
                         .requestMatchers("/riffs/song/**").permitAll()
                         .requestMatchers("/song**").permitAll()
                         .requestMatchers("/song/{id}").permitAll()
                         .requestMatchers("/riffs**").permitAll()
                         .requestMatchers("/pdf/**").permitAll()
-                        .requestMatchers("/appUsers*").hasAnyRole("ADMIN", "USER")
-                        .requestMatchers("/appUserRole*").hasRole("ADMIN")
-                        .requestMatchers("/exampleOne*").hasAuthority("ROLE_USER")
-                        .requestMatchers("/exampleTwo*").hasAnyAuthority("ROLE_STUDENT", "ROLE_ADMIN")
-                        .requestMatchers("/exampleThree*").hasRole("STUDENT")
                         .requestMatchers("/login*").anonymous()
-                        .requestMatchers("/register*").anonymous()
+                        .requestMatchers("/riffmaster/login*").anonymous()
                         .anyRequest().authenticated()
                 )
-                .formLogin(form -> form
-                        .loginPage("/login")
-                        .usernameParameter("login")
-                        .passwordParameter("password")
-                        .failureUrl("/login?error")
-                        .defaultSuccessUrl("/",true) //use wisely
-                        .permitAll()
-                )
                 .logout(logout -> logout
                         .logoutSuccessUrl("/login?logout")
                 )
@@ -111,10 +97,6 @@ public class SecurityConfiguration {
                 .httpBasic();//used to enable HTTP Basic authentication, which is a simple authentication scheme
                              // where the client sends the username and password in the HTTP header
         return http.build();
-
-//        .formLogin(form -> form
-//        .permitAll()
-//        )
     }
 
 }

+ 7 - 0
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/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.dmcs.jwoszczyk.security.CustomInterceptor;
 import pl.dmcs.jwoszczyk.service.IAddressService;
 import pl.dmcs.jwoszczyk.service.IAppUserRoleService;
 import pl.dmcs.jwoszczyk.utils.AddressConverter;
@@ -76,8 +77,10 @@ public class SpringConfiguration implements WebMvcConfigurer {
         LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
         interceptor.setParamName("lang");
         registry.addInterceptor(interceptor);
+        registry.addInterceptor(new CustomInterceptor());
     }
 
+
 //---------------------------------------------------------------------------------------validator
 
     //configure validator bean to read error codes from properties files
@@ -97,6 +100,10 @@ public class SpringConfiguration implements WebMvcConfigurer {
     @Resource(name="appUserRoleService")
     private IAppUserRoleService appUserRoleService;
 
+
+
+
+
     @Override
     public void addFormatters(FormatterRegistry formatterRegistry)
     {

+ 157 - 0
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/security/CustomInterceptor.java

@@ -0,0 +1,157 @@
+package pl.dmcs.jwoszczyk.security;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class CustomInterceptor implements HandlerInterceptor {
+    // endpoints
+    private Map<String, Map<String, Set<String>>> endpointRoles = new HashMap<>();
+
+    public CustomInterceptor() {
+        Map<String, Set<String>> songRoles = new HashMap<>();
+        songRoles.put("GET", Set.of("ROLE_USER", "ROLE_MODERATOR", "ROLE_ADMIN"));
+        songRoles.put("POST", Set.of("ROLE_USER", "ROLE_MODERATOR", "ROLE_ADMIN"));
+        songRoles.put("PUT", Set.of("ROLE_MODERATOR", "ROLE_ADMIN"));
+        songRoles.put("DELETE", Set.of("ROLE_MODERATOR", "ROLE_ADMIN"));
+        endpointRoles.put("/song", songRoles);
+
+        Map<String, Set<String>> riffRoles = new HashMap<>();
+        riffRoles.put("GET", Set.of("ROLE_USER", "ROLE_MODERATOR", "ROLE_ADMIN"));
+        riffRoles.put("POST", Set.of("ROLE_USER", "ROLE_MODERATOR", "ROLE_ADMIN"));
+        riffRoles.put("PUT", Set.of("ROLE_MODERATOR", "ROLE_ADMIN"));
+        riffRoles.put("DELETE", Set.of("ROLE_MODERATOR", "ROLE_ADMIN"));
+        endpointRoles.put("/riffs", riffRoles);
+
+        Map<String, Set<String>> userRoles = new HashMap<>();
+        userRoles.put("GET", Set.of("ROLE_USER", "ROLE_MODERATOR", "ROLE_ADMIN"));
+        userRoles.put("POST", Set.of("ROLE_ADMIN"));
+        userRoles.put("PUT", Set.of("ROLE_ADMIN"));
+        userRoles.put("DELETE", Set.of("ROLE_ADMIN"));
+        endpointRoles.put("/users", userRoles);
+
+
+    }
+
+
+    private final List<String> noAuth = List.of( "/riffmaster/login",
+                                                 "/register");// Endpoints that require no authorization
+
+
+
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+
+        System.out.println("\n#######################################################################START PRE HANDLING A REQUEST");
+        if (Objects.equals(request.getMethod(), "OPTIONS")) {
+            response.setHeader("Access-Control-Allow-Origin", "*");
+            response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
+            response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
+            response.setHeader("Access-Control-Max-Age", "3600");
+            return true;
+        }
+        System.out.println("test: " + request.getHeader("access-control-request-headers"));
+        System.out.println("test here: " + request.getHeader("access-control-request-headers.authorization"));
+
+        String endpoint = request.getRequestURI();
+//        System.out.println(request.getHeaderNames().toString());
+        Enumeration<String> headerNames = request.getHeaderNames();
+        while (headerNames.hasMoreElements()) {
+            String headerName = headerNames.nextElement();
+            String headerValue = request.getHeader(headerName);
+            System.out.println(headerName + ": " + headerValue);
+        }
+
+
+        if (noAuth.contains(endpoint)) {
+            System.out.println("no auth required for this request\n");
+            return HandlerInterceptor.super.preHandle(request, response, handler);
+        }
+        else
+        {
+            try{
+                System.out.println("authorization needed");
+
+
+                 String token = request.getHeader("Authorization").split(" ")[1];
+
+
+                if (JwtTokenUtil.validateToken(token))
+                {
+                    System.out.println("    token is valid\n");
+
+                    //-------------------------------------------------------get roles
+                    String method = request.getMethod();
+                    Set<String> userRoles = JwtTokenUtil.getRolesFromToken(token);
+                    System.out.println("reHandle mehod");
+                    //-------------------------------------------------------check user authority
+
+                    if (isAuthorized(endpoint, method, userRoles)) {
+                        System.out.println("preauthorizing reuqst");
+                        return HandlerInterceptor.super.preHandle(request, response, handler);
+                    }
+                    else {
+                        response.setStatus(HttpStatus.FORBIDDEN.value());
+                        response.getWriter().write("Unauthorized access");
+                        return false;
+                    }
+                }
+                else // token not valid
+                {
+                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
+                    response.getWriter().write("Invalid token");
+                    return false;
+                }
+
+
+            }
+            catch (NullPointerException e) {
+                System.out.println(e);
+                response.setStatus(HttpStatus.UNAUTHORIZED.value());
+                response.getWriter().write("Empty header");
+            }
+            catch (Exception e) {
+                System.out.println(e);
+                response.setStatus(HttpStatus.UNAUTHORIZED.value());
+                response.getWriter().write("Missing authorization header");
+            return false;
+            }
+
+        }
+        return false;
+    }
+
+    private boolean isAuthorized(String endpoint, String method, Set<String> roles) {
+        System.out.println("Authorization in isAuthorized() method");
+        System.out.println("    endpoint: " + endpoint);
+        System.out.println("    method: " + method);
+        System.out.println("    roles: " + roles);
+
+
+        Map<String, Set<String>> methodRoles = endpointRoles.get(endpoint);
+        if (methodRoles != null) {
+            Set<String> requiredRoles = methodRoles.get(method);
+            if (requiredRoles != null) {
+                return !Collections.disjoint(roles, requiredRoles);
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
+    }
+}

+ 28 - 7
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/security/JwtTokenUtil.java

@@ -7,6 +7,8 @@ import io.jsonwebtoken.SignatureAlgorithm;
 import org.springframework.stereotype.Component;
 
 import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.function.Function;
 
@@ -15,24 +17,25 @@ 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
+    private static final long EXPIRATION_TIME = 1000 * 60; // 60 sec
 
     public static String generateToken(String username, Set<String> roles) {
-        // Set token expiration time
+        // ---------------------------------------------------------------Set token expiration time
+
         Date expirationDate = new Date(System.currentTimeMillis() + EXPIRATION_TIME);
 
-        // Build the JWT claims
+        // ---------------------------------------------------------------Build the JWT claims
+
         Claims claims = Jwts.claims().setSubject(username);
         claims.put("roles", roles);
 
-        // Build the JWT
+        // ---------------------------------------------------------------Build the JWT
         JwtBuilder jwtBuilder = Jwts.builder()
                 .setClaims(claims)
                 .setIssuedAt(new Date())
                 .setExpiration(expirationDate)
                 .signWith(SignatureAlgorithm.HS256, SECRET_KEY);
 
-        // Generate the token
         return jwtBuilder.compact();
     }
 
@@ -57,6 +60,18 @@ public class JwtTokenUtil {
         return getClaimFromToken(token, Claims::getSubject);
     }
 
+    public static Set<String> getRolesFromToken(String token) {
+        System.out.println("         getRolesFromToken()");
+
+        Claims claims = getAllClaimsFromToken(token);
+        List<String> roles = claims.get("roles", List.class);
+
+        System.out.println("        claims: " + claims);
+        System.out.println("        claims(list): " + roles);
+
+        return new HashSet<>(roles);
+    }
+
 
     public Date getExpirationDateFromToken(String token) {
         return getClaimFromToken(token, Claims::getExpiration);
@@ -67,7 +82,13 @@ public class JwtTokenUtil {
         return claimsResolver.apply(claims);
     }
 
-    private Claims getAllClaimsFromToken(String token) {
-        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
+    private static Claims getAllClaimsFromToken(String token) {
+        System.out.println("getAllClaimsFromToken()");
+        // Remove whitespace characters from the token string
+        String trimmedToken = token.trim();
+
+        System.out.println("        trimmed token: " + trimmedToken + "\n\n");
+        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(trimmedToken).getBody();
     }
+
 }

binární
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.class


binární
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/configuration/SpringConfiguration.class


binární
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/security/CustomInterceptor.class


binární
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/security/JwtTokenUtil.class


binární
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.class


binární
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/configuration/SpringConfiguration.class


binární
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/security/CustomInterceptor.class


binární
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/security/JwtTokenUtil.class


binární
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/12.pack


binární
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/17.pack


binární
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/2.pack


binární
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/7.pack


binární
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/8.pack


binární
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack


binární
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack.old


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/287cf156bc7a9c92e86ba699635233092fa675ca3f3c2622e456a3a0172ce17d.json


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/405365a0d40ce49e4002a4bce7027e4038affd582987e7aa218eece675e9eb41.json


+ 4 - 2
Frontend/RiffMasterFront/.idea/workspace.xml

@@ -6,7 +6,9 @@
   <component name="ChangeListManager">
     <list default="true" id="d91bc08d-d968-4797-8fb3-ef602a37db2a" name="Changes" comment="RIFFMASTER: add frontend business logic (riff, song)">
       <change beforePath="$PROJECT_DIR$/../../Backend/Spring/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/controller/SecurityController.java" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/controller/SecurityController.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.java" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/configuration/SpringConfiguration.java" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/configuration/SpringConfiguration.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/security/JwtTokenUtil.java" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/security/JwtTokenUtil.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -113,7 +115,7 @@
       <workItem from="1687011087000" duration="9476000" />
       <workItem from="1687039479377" duration="859000" />
       <workItem from="1687040351475" duration="221000" />
-      <workItem from="1687069506147" duration="8276000" />
+      <workItem from="1687069506147" duration="9763000" />
     </task>
     <task id="LOCAL-00001" summary="RIFFMASTER: add frontend project">
       <created>1685976235580</created>

+ 5 - 1
Frontend/RiffMasterFront/src/app/Services/song.service.ts

@@ -14,7 +14,11 @@ export class SongService {
   constructor(private http: HttpClient) {}
 
   getAllSongs(): Observable<Song[]> {
-    return this.http.get<Song[]>(this.apiUrl);
+    const headers = new HttpHeaders()
+      .set('Content-Type', 'application/json')
+      .set('Authorization', sessionStorage.getItem("jwtToken")!);
+
+    return this.http.get<Song[]>(this.apiUrl, {headers});
   }
 
 

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů