Skip to content

Commit e17372c

Browse files
authored
Merge pull request #6 from alwinsimon/v1-dev
V1 dev - Completed Auth Configurations.
2 parents 5c1b73d + 4acd099 commit e17372c

17 files changed

+679
-12
lines changed

pom.xml

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424

2525
<dependency>
2626
<groupId>org.springframework.boot</groupId>
27-
<artifactId>spring-boot-starter-test</artifactId>
28-
<scope>test</scope>
27+
<artifactId>spring-boot-starter-security</artifactId>
2928
</dependency>
3029

3130
<dependency>
@@ -38,6 +37,42 @@
3837
<artifactId>postgresql</artifactId>
3938
<scope>runtime</scope>
4039
</dependency>
40+
41+
<dependency>
42+
<groupId>org.projectlombok</groupId>
43+
<artifactId>lombok</artifactId>
44+
<optional>true</optional>
45+
</dependency>
46+
47+
<dependency>
48+
<groupId>io.jsonwebtoken</groupId>
49+
<artifactId>jjwt-api</artifactId>
50+
<version>0.11.5</version>
51+
</dependency>
52+
53+
<dependency>
54+
<groupId>io.jsonwebtoken</groupId>
55+
<artifactId>jjwt-impl</artifactId>
56+
<version>0.11.5</version>
57+
</dependency>
58+
59+
<dependency>
60+
<groupId>io.jsonwebtoken</groupId>
61+
<artifactId>jjwt-jackson</artifactId>
62+
<version>0.11.5</version>
63+
</dependency>
64+
65+
<dependency>
66+
<groupId>org.springframework.boot</groupId>
67+
<artifactId>spring-boot-starter-test</artifactId>
68+
<scope>test</scope>
69+
</dependency>
70+
71+
<dependency>
72+
<groupId>org.springframework.security</groupId>
73+
<artifactId>spring-security-test</artifactId>
74+
<scope>test</scope>
75+
</dependency>
4176
</dependencies>
4277

4378
<build>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.alwinsimon.UserManagementJavaSpringBoot.Config;
2+
3+
import com.alwinsimon.UserManagementJavaSpringBoot.Repository.UserRepository;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.security.authentication.AuthenticationManager;
8+
import org.springframework.security.authentication.AuthenticationProvider;
9+
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
10+
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
11+
import org.springframework.security.core.context.SecurityContextHolder;
12+
import org.springframework.security.core.userdetails.UserDetailsService;
13+
import org.springframework.security.core.userdetails.UsernameNotFoundException;
14+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
15+
import org.springframework.security.crypto.password.PasswordEncoder;
16+
17+
import java.security.Principal;
18+
19+
@Configuration
20+
@RequiredArgsConstructor
21+
public class ApplicationConfig {
22+
23+
private final UserRepository userRepository;
24+
25+
@Bean
26+
public UserDetailsService userDetailsService() {
27+
28+
return username -> userRepository.findByEmail(username)
29+
.orElseThrow(() -> new UsernameNotFoundException("User not found."));
30+
}
31+
32+
@Bean
33+
public PasswordEncoder passwordEncoder() {
34+
35+
return new BCryptPasswordEncoder();
36+
37+
}
38+
39+
@Bean
40+
public AuthenticationProvider authenticationProvider() {
41+
42+
// Creating an authentication provider with Data Access Object Authentication Provider
43+
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
44+
45+
// Configuring authProvider
46+
authProvider.setUserDetailsService(userDetailsService());
47+
authProvider.setPasswordEncoder(passwordEncoder());
48+
49+
return authProvider;
50+
51+
}
52+
53+
@Bean
54+
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
55+
56+
return authenticationConfiguration.getAuthenticationManager();
57+
58+
}
59+
60+
@Bean
61+
public Principal principal() throws Exception {
62+
return () -> SecurityContextHolder.getContext().getAuthentication().getName();
63+
}
64+
65+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
@Data
9+
@Builder
10+
@AllArgsConstructor
11+
@NoArgsConstructor
12+
public class AuthenticationRequest {
13+
14+
private String email;
15+
16+
private String password;
17+
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
@Data
9+
@Builder
10+
@AllArgsConstructor
11+
@NoArgsConstructor
12+
public class AuthenticationResponse {
13+
14+
private String token;
15+
16+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.lang.Nullable;
6+
import org.springframework.web.cors.CorsConfiguration;
7+
import org.springframework.web.cors.CorsConfigurationSource;
8+
9+
import java.util.Arrays;
10+
import java.util.Collections;
11+
12+
@Configuration
13+
public class CorsConfig implements CorsConfigurationSource {
14+
15+
@Override
16+
@Nullable
17+
public CorsConfiguration getCorsConfiguration(HttpServletRequest arg0) {
18+
CorsConfiguration config = new CorsConfiguration();
19+
config.setAllowedOrigins(Collections.singletonList("*"));
20+
config.setAllowedMethods(Collections.singletonList("*"));
21+
config.setAllowCredentials(true);
22+
config.setAllowedHeaders(Collections.singletonList("*"));
23+
config.setExposedHeaders(Arrays.asList("Authorization"));
24+
config.setMaxAge(3600L);
25+
26+
return config;
27+
}
28+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
@Data
9+
@Builder
10+
@AllArgsConstructor
11+
@NoArgsConstructor
12+
public class RegisterRequest {
13+
14+
private String name;
15+
16+
private String gender;
17+
18+
private String email;
19+
20+
private String password;
21+
22+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.alwinsimon.UserManagementJavaSpringBoot.Config.Filter;
2+
3+
import com.alwinsimon.UserManagementJavaSpringBoot.Service.JwtService;
4+
import jakarta.servlet.FilterChain;
5+
import jakarta.servlet.ServletException;
6+
import jakarta.servlet.http.HttpServletRequest;
7+
import jakarta.servlet.http.HttpServletResponse;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.lang.NonNull;
10+
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
11+
import org.springframework.security.core.context.SecurityContextHolder;
12+
import org.springframework.security.core.userdetails.UserDetails;
13+
import org.springframework.security.core.userdetails.UserDetailsService;
14+
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
15+
import org.springframework.stereotype.Component;
16+
import org.springframework.web.filter.OncePerRequestFilter;
17+
18+
import java.io.IOException;
19+
20+
@Component
21+
@RequiredArgsConstructor
22+
public class JwtAuthenticationFilter extends OncePerRequestFilter {
23+
24+
private final JwtService jwtService;
25+
private final UserDetailsService userDetailsService;
26+
27+
@Override
28+
protected void doFilterInternal(
29+
@NonNull HttpServletRequest request,
30+
@NonNull HttpServletResponse response,
31+
@NonNull FilterChain filterChain
32+
) throws ServletException, IOException {
33+
34+
final String jwtFromRequest;
35+
final String authHeaderFromRequest;
36+
final String userEmail;
37+
38+
// Try to parse JWT from the request header if it exists.
39+
authHeaderFromRequest = request.getHeader("Authorization");
40+
41+
// Return early if there is no valid authorization header.
42+
if (authHeaderFromRequest == null || !authHeaderFromRequest.startsWith("Bearer ")) {
43+
filterChain.doFilter(request, response);
44+
return;
45+
}
46+
47+
// Parse and store JWT Token received from Authorisation Header.
48+
jwtFromRequest = authHeaderFromRequest.substring(7);
49+
50+
// Decrypt Token and find user email from token claims
51+
userEmail = jwtService.extractUsername(jwtFromRequest);
52+
53+
if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
54+
// Fetch user details from DB using userDetailsService.
55+
UserDetails userDetails = this.userDetailsService.loadUserByUsername(userEmail);
56+
57+
if (jwtService.isTokenValid(jwtFromRequest, userDetails)) {
58+
// Authenticate user as the Token is Valid
59+
60+
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
61+
userDetails,
62+
null,
63+
userDetails.getAuthorities()
64+
);
65+
66+
authToken.setDetails(
67+
new WebAuthenticationDetailsSource().buildDetails(request)
68+
);
69+
70+
// Update Security Context Holder with authToken
71+
SecurityContextHolder.getContext().setAuthentication(authToken);
72+
73+
}
74+
}
75+
76+
// Passing the control to next filters for continuation of execution.
77+
filterChain.doFilter(request, response);
78+
79+
}
80+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.alwinsimon.UserManagementJavaSpringBoot.Config;
2+
3+
import com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth.CorsConfig;
4+
import com.alwinsimon.UserManagementJavaSpringBoot.Config.Filter.JwtAuthenticationFilter;
5+
import lombok.RequiredArgsConstructor;
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.security.authentication.AuthenticationProvider;
10+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
11+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
12+
import org.springframework.security.config.http.SessionCreationPolicy;
13+
import org.springframework.security.web.SecurityFilterChain;
14+
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
15+
16+
@Configuration
17+
@EnableWebSecurity
18+
@RequiredArgsConstructor
19+
public class SecurityConfig {
20+
21+
private final JwtAuthenticationFilter jwtAuthenticationFilter;
22+
private final AuthenticationProvider authenticationProvider;
23+
24+
@Autowired
25+
private CorsConfig corsConfig;
26+
27+
@Bean
28+
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
29+
30+
http
31+
.csrf((csrf) -> csrf.disable())
32+
.cors(cors -> cors.configurationSource(corsConfig))
33+
.authorizeHttpRequests(authorize -> authorize
34+
.requestMatchers("/health/", "/api/v1/auth/**")
35+
.permitAll()
36+
.anyRequest()
37+
.authenticated()
38+
)
39+
.sessionManagement((session) -> session
40+
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
41+
)
42+
.authenticationProvider(authenticationProvider)
43+
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
44+
45+
return http.build();
46+
}
47+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.alwinsimon.UserManagementJavaSpringBoot.Controller;
2+
3+
import com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth.AuthenticationRequest;
4+
import com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth.AuthenticationResponse;
5+
import com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth.RegisterRequest;
6+
import com.alwinsimon.UserManagementJavaSpringBoot.Service.AuthenticationService;
7+
import lombok.RequiredArgsConstructor;
8+
import org.springframework.http.ResponseEntity;
9+
import org.springframework.web.bind.annotation.PostMapping;
10+
import org.springframework.web.bind.annotation.RequestBody;
11+
import org.springframework.web.bind.annotation.RequestMapping;
12+
import org.springframework.web.bind.annotation.RestController;
13+
14+
@RestController
15+
@RequestMapping("/api/v1/auth")
16+
@RequiredArgsConstructor
17+
public class AuthenticationController {
18+
19+
private final AuthenticationService authenticationService;
20+
21+
@PostMapping("/register")
22+
public ResponseEntity<AuthenticationResponse> register(
23+
@RequestBody RegisterRequest request
24+
) {
25+
26+
return ResponseEntity.ok(authenticationService.register(request));
27+
28+
}
29+
30+
@PostMapping("/authenticate")
31+
public ResponseEntity<AuthenticationResponse> authenticate(
32+
@RequestBody AuthenticationRequest request
33+
) {
34+
35+
return ResponseEntity.ok(authenticationService.authenticate(request));
36+
37+
}
38+
39+
}

0 commit comments

Comments
 (0)