Преглед на файлове

Request and response payloads added

JaseG256 преди 6 години
родител
ревизия
797d1950fc

+ 4
- 1
ZipTeamOrange-server/pom.xml Целия файл

@@ -42,7 +42,10 @@
42 42
 			<groupId>org.springframework.boot</groupId>
43 43
 			<artifactId>spring-boot-starter-web</artifactId>
44 44
 		</dependency>
45
-
45
+		<dependency>
46
+			<groupId>org.springframework.boot</groupId>
47
+			<artifactId>spring-boot-starter-security</artifactId>
48
+		</dependency>
46 49
 		<dependency>
47 50
 			<groupId>org.springframework.boot</groupId>
48 51
 			<artifactId>spring-boot-starter-data-rest</artifactId>

+ 96
- 0
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Config/SecurityConfig.java Целия файл

@@ -0,0 +1,96 @@
1
+package ZipTeamOrange.Config;
2
+
3
+import ZipTeamOrange.Security.CustomUserDetailsService;
4
+import ZipTeamOrange.Security.JwtAuthenticationEntryPoint;
5
+import ZipTeamOrange.Security.JwtAuthenticationFilter;
6
+import org.springframework.beans.factory.annotation.Autowired;
7
+import org.springframework.context.annotation.Bean;
8
+import org.springframework.context.annotation.Configuration;
9
+import org.springframework.http.HttpMethod;
10
+import org.springframework.security.authentication.AuthenticationManager;
11
+import org.springframework.security.config.BeanIds;
12
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
13
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
14
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
15
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
16
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
17
+import org.springframework.security.config.http.SessionCreationPolicy;
18
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
19
+import org.springframework.security.crypto.password.PasswordEncoder;
20
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
21
+
22
+@Configuration
23
+@EnableWebSecurity
24
+@EnableGlobalMethodSecurity(
25
+        securedEnabled = true,
26
+        jsr250Enabled = true,
27
+        prePostEnabled = true
28
+)
29
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
30
+    @Autowired
31
+    CustomUserDetailsService customUserDetailsService;
32
+
33
+    @Autowired
34
+    private JwtAuthenticationEntryPoint unauthorizedHandler;
35
+
36
+    @Bean
37
+    public JwtAuthenticationFilter jwtAuthenticationFilter() {
38
+        return new JwtAuthenticationFilter();
39
+    }
40
+
41
+    @Override
42
+    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
43
+        authenticationManagerBuilder
44
+                .userDetailsService(customUserDetailsService)
45
+                .passwordEncoder(passwordEncoder());
46
+    }
47
+
48
+    @Bean(BeanIds.AUTHENTICATION_MANAGER)
49
+    @Override
50
+    public AuthenticationManager authenticationManagerBean() throws Exception {
51
+        return super.authenticationManagerBean();
52
+    }
53
+
54
+    @Bean
55
+    public PasswordEncoder passwordEncoder() {
56
+        return new BCryptPasswordEncoder();
57
+    }
58
+
59
+    @Override
60
+    protected void configure(HttpSecurity http) throws Exception {
61
+        http
62
+                .cors()
63
+                .and()
64
+                .csrf()
65
+                .disable()
66
+                .exceptionHandling()
67
+                .authenticationEntryPoint(unauthorizedHandler)
68
+                .and()
69
+                .sessionManagement()
70
+                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
71
+                .and()
72
+                .authorizeRequests()
73
+                .antMatchers("/",
74
+                        "/favicon.ico",
75
+                        "/**/*.png",
76
+                        "/**/*.gif",
77
+                        "/**/*.svg",
78
+                        "/**/*.jpg",
79
+                        "/**/*.html",
80
+                        "/**/*.css",
81
+                        "/**/*.js")
82
+                .permitAll()
83
+                .antMatchers("/api/auth/**")
84
+                .permitAll()
85
+                .antMatchers("/api/user/checkUsernameAvailability", "/api/user/checkEmailAvailability")
86
+                .permitAll()
87
+                .antMatchers(HttpMethod.GET, "/api/polls/**", "/api/users/**")
88
+                .permitAll()
89
+                .anyRequest()
90
+                .authenticated();
91
+
92
+        // Add our custom JWT security filter
93
+        http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
94
+
95
+    }
96
+}

+ 2
- 2
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Model/User.java Целия файл

@@ -72,11 +72,11 @@ public class User extends DateAudit{
72 72
         this.id = id;
73 73
     }
74 74
 
75
-    public String getUserName() {
75
+    public String getUsername() {
76 76
         return username;
77 77
     }
78 78
 
79
-    public void setUserName(String userName) {
79
+    public void setUsername(String userName) {
80 80
         this.username = userName;
81 81
     }
82 82
 

+ 27
- 0
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Payload/ApiResponse.java Целия файл

@@ -0,0 +1,27 @@
1
+package ZipTeamOrange.Payload;
2
+
3
+public class ApiResponse {
4
+    private Boolean success;
5
+    private String message;
6
+
7
+    public ApiResponse(Boolean success, String message) {
8
+        this.success = success;
9
+        this.message = message;
10
+    }
11
+
12
+    public Boolean getSuccess() {
13
+        return success;
14
+    }
15
+
16
+    public void setSuccess(Boolean success) {
17
+        this.success = success;
18
+    }
19
+
20
+    public String getMessage() {
21
+        return message;
22
+    }
23
+
24
+    public void setMessage(String message) {
25
+        this.message = message;
26
+    }
27
+}

+ 26
- 0
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Payload/JwtAuthenticationResponse.java Целия файл

@@ -0,0 +1,26 @@
1
+package ZipTeamOrange.Payload;
2
+
3
+public class JwtAuthenticationResponse {
4
+    private String accessToken;
5
+    private String tokenType = "Bearer";
6
+
7
+    public JwtAuthenticationResponse(String accessToken) {
8
+        this.accessToken = accessToken;
9
+    }
10
+
11
+    public String getAccessToken() {
12
+        return accessToken;
13
+    }
14
+
15
+    public void setAccessToken(String accessToken) {
16
+        this.accessToken = accessToken;
17
+    }
18
+
19
+    public String getTokenType() {
20
+        return tokenType;
21
+    }
22
+
23
+    public void setTokenType(String tokenType) {
24
+        this.tokenType = tokenType;
25
+    }
26
+}

+ 27
- 0
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Payload/LoginRequest.java Целия файл

@@ -0,0 +1,27 @@
1
+package ZipTeamOrange.Payload;
2
+
3
+import javax.validation.constraints.NotBlank;
4
+
5
+public class LoginRequest {
6
+    @NotBlank
7
+    private String usernameOrEmail;
8
+
9
+    @NotBlank
10
+    private String password;
11
+
12
+    public String getUsernameOrEmail() {
13
+        return usernameOrEmail;
14
+    }
15
+
16
+    public void setUsernameOrEmail(String usernameOrEmail) {
17
+        this.usernameOrEmail = usernameOrEmail;
18
+    }
19
+
20
+    public String getPassword() {
21
+        return password;
22
+    }
23
+
24
+    public void setPassword(String password) {
25
+        this.password = password;
26
+    }
27
+}

+ 56
- 0
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Payload/SignUpRequest.java Целия файл

@@ -0,0 +1,56 @@
1
+package ZipTeamOrange.Payload;
2
+
3
+import javax.validation.constraints.Email;
4
+import javax.validation.constraints.NotBlank;
5
+import javax.validation.constraints.Size;
6
+
7
+public class SignUpRequest {
8
+    @NotBlank
9
+    @Size(min = 4, max = 40)
10
+    private String name;
11
+
12
+    @NotBlank
13
+    @Size(min = 3, max = 15)
14
+    private String username;
15
+
16
+    @NotBlank
17
+    @Size(max = 40)
18
+    @Email
19
+    private String email;
20
+
21
+    @NotBlank
22
+    @Size(min = 6, max = 20)
23
+    private String password;
24
+
25
+    public String getName() {
26
+        return name;
27
+    }
28
+
29
+    public void setName(String name) {
30
+        this.name = name;
31
+    }
32
+
33
+    public String getUsername() {
34
+        return username;
35
+    }
36
+
37
+    public void setUsername(String username) {
38
+        this.username = username;
39
+    }
40
+
41
+    public String getEmail() {
42
+        return email;
43
+    }
44
+
45
+    public void setEmail(String email) {
46
+        this.email = email;
47
+    }
48
+
49
+    public String getPassword() {
50
+        return password;
51
+    }
52
+
53
+    public void setPassword(String password) {
54
+        this.password = password;
55
+    }
56
+}

+ 13
- 0
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Security/CurrentUser.java Целия файл

@@ -0,0 +1,13 @@
1
+package ZipTeamOrange.Security;
2
+
3
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
4
+
5
+import java.lang.annotation.*;
6
+
7
+@Target({ElementType.PARAMETER, ElementType.TYPE})
8
+@Retention(RetentionPolicy.RUNTIME)
9
+@Documented
10
+@AuthenticationPrincipal
11
+public @interface CurrentUser {
12
+
13
+}

+ 41
- 0
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Security/CustomUserDetailsService.java Целия файл

@@ -0,0 +1,41 @@
1
+package ZipTeamOrange.Security;
2
+
3
+import ZipTeamOrange.Model.User;
4
+import ZipTeamOrange.Repository.UserRepository;
5
+import org.springframework.beans.factory.annotation.Autowired;
6
+import org.springframework.security.core.userdetails.UserDetails;
7
+import org.springframework.security.core.userdetails.UserDetailsService;
8
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
9
+import org.springframework.stereotype.Service;
10
+import org.springframework.transaction.annotation.Transactional;
11
+
12
+@Service
13
+public class CustomUserDetailsService implements UserDetailsService {
14
+
15
+    @Autowired
16
+    UserRepository userRepository;
17
+
18
+    @Override
19
+    @Transactional
20
+    public UserDetails loadUserByUsername(String usernameOrEmail)
21
+            throws UsernameNotFoundException {
22
+        // Let people login with either username or email
23
+        User user = userRepository.findByUsernameOrEmail(usernameOrEmail, usernameOrEmail)
24
+                .orElseThrow(() ->
25
+                        new UsernameNotFoundException("User not found with username or email : " + usernameOrEmail)
26
+                );
27
+
28
+        return UserPrincipal.create(user);
29
+    }
30
+
31
+    // This method is used by JWTAuthenticationFilter
32
+    @Transactional
33
+    public UserDetails loadUserById(Long id) {
34
+        User user = userRepository.findById(id).orElseThrow(
35
+                () -> new UsernameNotFoundException("User not found with id : " + id)
36
+        );
37
+
38
+        return UserPrincipal.create(user);
39
+    }
40
+}
41
+

+ 26
- 0
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Security/JwtAuthenticationEntryPoint.java Целия файл

@@ -0,0 +1,26 @@
1
+package ZipTeamOrange.Security;
2
+
3
+import org.slf4j.Logger;
4
+import org.slf4j.LoggerFactory;
5
+import org.springframework.security.core.AuthenticationException;
6
+import org.springframework.security.web.AuthenticationEntryPoint;
7
+import org.springframework.stereotype.Component;
8
+
9
+import javax.servlet.ServletException;
10
+import javax.servlet.http.HttpServletRequest;
11
+import javax.servlet.http.HttpServletResponse;
12
+import java.io.IOException;
13
+
14
+@Component
15
+public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
16
+
17
+    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);
18
+    @Override
19
+    public void commence(HttpServletRequest httpServletRequest,
20
+                         HttpServletResponse httpServletResponse,
21
+                         AuthenticationException e) throws IOException, ServletException {
22
+        logger.error("Responding with unauthorized error. Message - {}", e.getMessage());
23
+        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
24
+                "Sorry, You're not authorized to access this resource.");
25
+    }
26
+}

+ 58
- 0
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Security/JwtAuthenticationFilter.java Целия файл

@@ -0,0 +1,58 @@
1
+package ZipTeamOrange.Security;
2
+
3
+import org.slf4j.Logger;
4
+import org.slf4j.LoggerFactory;
5
+import org.springframework.beans.factory.annotation.Autowired;
6
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
7
+import org.springframework.security.core.context.SecurityContextHolder;
8
+import org.springframework.security.core.userdetails.UserDetails;
9
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
10
+import org.springframework.util.StringUtils;
11
+import org.springframework.web.filter.OncePerRequestFilter;
12
+
13
+import javax.servlet.FilterChain;
14
+import javax.servlet.ServletException;
15
+import javax.servlet.http.HttpServletRequest;
16
+import javax.servlet.http.HttpServletResponse;
17
+import java.io.IOException;
18
+
19
+public class JwtAuthenticationFilter extends OncePerRequestFilter {
20
+
21
+    @Autowired
22
+    private JwtTokenProvider tokenProvider;
23
+
24
+    @Autowired
25
+    private CustomUserDetailsService customUserDetailsService;
26
+
27
+    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
28
+
29
+    @Override
30
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
31
+        try {
32
+            String jwt = getJwtFromRequest(request);
33
+
34
+            if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
35
+                Long userId = tokenProvider.getUserIdFromJWT(jwt);
36
+
37
+                UserDetails userDetails = customUserDetailsService.loadUserById(userId);
38
+                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
39
+                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
40
+
41
+                SecurityContextHolder.getContext().setAuthentication(authentication);
42
+            }
43
+        } catch (Exception ex) {
44
+            logger.error("Could not set user authentication in security context", ex);
45
+        }
46
+
47
+        filterChain.doFilter(request, response);
48
+    }
49
+
50
+    private String getJwtFromRequest(HttpServletRequest request) {
51
+        String bearerToken = request.getHeader("Authorization");
52
+        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
53
+            return bearerToken.substring(7, bearerToken.length());
54
+        }
55
+        return null;
56
+    }
57
+}
58
+

+ 64
- 0
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Security/JwtTokenProvider.java Целия файл

@@ -0,0 +1,64 @@
1
+package ZipTeamOrange.Security;
2
+
3
+import io.jsonwebtoken.*;
4
+import org.slf4j.Logger;
5
+import org.slf4j.LoggerFactory;
6
+import org.springframework.beans.factory.annotation.Value;
7
+import org.springframework.security.core.Authentication;
8
+import org.springframework.stereotype.Component;
9
+
10
+import java.util.Date;
11
+
12
+@Component
13
+public class JwtTokenProvider {
14
+
15
+    private static final Logger logger = LoggerFactory.getLogger(JwtTokenProvider.class);
16
+
17
+    @Value("${app.jwtSecret}")
18
+    private String jwtSecret;
19
+
20
+    @Value("${app.jwtExpirationInMs}")
21
+    private int jwtExpirationInMs;
22
+
23
+    public String generateToken(Authentication authentication) {
24
+
25
+        UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
26
+
27
+        Date now = new Date();
28
+        Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);
29
+
30
+        return Jwts.builder()
31
+                .setSubject(Long.toString(userPrincipal.getId()))
32
+                .setIssuedAt(new Date())
33
+                .setExpiration(expiryDate)
34
+                .signWith(SignatureAlgorithm.HS512, jwtSecret)
35
+                .compact();
36
+    }
37
+
38
+    public Long getUserIdFromJWT(String token) {
39
+        Claims claims = Jwts.parser()
40
+                .setSigningKey(jwtSecret)
41
+                .parseClaimsJws(token)
42
+                .getBody();
43
+
44
+        return Long.parseLong(claims.getSubject());
45
+    }
46
+
47
+    public boolean validateToken(String authToken) {
48
+        try {
49
+            Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
50
+            return true;
51
+        } catch (SignatureException ex) {
52
+            logger.error("Invalid JWT signature");
53
+        } catch (MalformedJwtException ex) {
54
+            logger.error("Invalid JWT token");
55
+        } catch (ExpiredJwtException ex) {
56
+            logger.error("Expired JWT token");
57
+        } catch (UnsupportedJwtException ex) {
58
+            logger.error("Unsupported JWT token");
59
+        } catch (IllegalArgumentException ex) {
60
+            logger.error("JWT claims string is empty.");
61
+        }
62
+        return false;
63
+    }
64
+}

+ 107
- 0
ZipTeamOrange-server/src/main/java/ZipTeamOrange/Security/UserPrincipal.java Целия файл

@@ -0,0 +1,107 @@
1
+package ZipTeamOrange.Security;
2
+
3
+import ZipTeamOrange.Model.User;
4
+import com.fasterxml.jackson.annotation.JsonIgnore;
5
+import org.springframework.security.core.GrantedAuthority;
6
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
7
+import org.springframework.security.core.userdetails.UserDetails;
8
+
9
+import java.util.Collection;
10
+import java.util.List;
11
+import java.util.Objects;
12
+import java.util.stream.Collectors;
13
+
14
+public class UserPrincipal implements UserDetails {
15
+    private Long id;
16
+
17
+    private String name;
18
+
19
+    private String username;
20
+
21
+    @JsonIgnore
22
+    private String email;
23
+
24
+    @JsonIgnore
25
+    private String password;
26
+
27
+    private Collection<? extends GrantedAuthority> authorities;
28
+
29
+    public UserPrincipal(Long id, String username, String email, String password, Collection<? extends GrantedAuthority> authorities) {
30
+        this.id = id;
31
+        this.username = username;
32
+        this.email = email;
33
+        this.password = password;
34
+        this.authorities = authorities;
35
+    }
36
+
37
+    public static UserPrincipal create(User user) {
38
+        List<GrantedAuthority> authorities = user.getRoles().stream().map(role ->
39
+                new SimpleGrantedAuthority(role.getName().name())
40
+        ).collect(Collectors.toList());
41
+
42
+        return new UserPrincipal(
43
+                user.getId(),
44
+                user.getUsername(),
45
+                user.getEmail(),
46
+                user.getPassword(),
47
+                authorities
48
+        );
49
+    }
50
+
51
+    public Long getId() {
52
+        return id;
53
+    }
54
+
55
+    public String getEmail() {
56
+        return email;
57
+    }
58
+
59
+    @Override
60
+    public String getUsername() {
61
+        return username;
62
+    }
63
+
64
+    @Override
65
+    public String getPassword() {
66
+        return password;
67
+    }
68
+
69
+    @Override
70
+    public Collection<? extends GrantedAuthority> getAuthorities() {
71
+        return authorities;
72
+    }
73
+
74
+    @Override
75
+    public boolean isAccountNonExpired() {
76
+        return true;
77
+    }
78
+
79
+    @Override
80
+    public boolean isAccountNonLocked() {
81
+        return true;
82
+    }
83
+
84
+    @Override
85
+    public boolean isCredentialsNonExpired() {
86
+        return true;
87
+    }
88
+
89
+    @Override
90
+    public boolean isEnabled() {
91
+        return true;
92
+    }
93
+
94
+    @Override
95
+    public boolean equals(Object o) {
96
+        if (this == o) return true;
97
+        if (o == null || getClass() != o.getClass()) return false;
98
+        UserPrincipal that = (UserPrincipal) o;
99
+        return Objects.equals(id, that.id);
100
+    }
101
+
102
+    @Override
103
+    public int hashCode() {
104
+
105
+        return Objects.hash(id);
106
+    }
107
+}

+ 5
- 1
ZipTeamOrange-server/src/main/resources/application.properties Целия файл

@@ -12,4 +12,8 @@ logging.level.org.hibernate.SQL= DEBUG
12 12
 ## Jackson Properties
13 13
 spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS= false
14 14
 spring.jackson.time-zone= UTC
15
-logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
15
+logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
16
+
17
+## App Properties
18
+app.jwtSecret= JWTSuperSecretKey
19
+app.jwtExpirationInMs = 604800000