Skip to content

Commit

Permalink
Add JWT authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
Trinh-Tan-Dat committed Sep 4, 2024
1 parent c97cae2 commit 337c06e
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 22 deletions.
19 changes: 17 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,23 @@
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>


<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version> <!-- Hoặc phiên bản mới nhất -->
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- Hoặc jjwt-gson nếu bạn dùng Gson -->
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>



Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.programming.userService.config;

import com.programming.userService.util.JwtUtil;
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.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@Component
public class JwtRequestFilter extends OncePerRequestFilter {

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private JwtUtil jwtUtil;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {

final String authorizationHeader = request.getHeader("Authorization");

String username = null;
String jwt = null;

if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}

if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

if (jwtUtil.validateToken(jwt, userDetails)) {

UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -21,25 +22,26 @@ public class SecurityConfig {

@Bean
public SecurityFilterChain defaultFilterChain(HttpSecurity httpSecurity) throws Exception {
JwtRequestFilter jwtRequestFilter = new JwtRequestFilter();
return httpSecurity
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth.requestMatchers("/register", "/error").permitAll()
.requestMatchers("/listUser").permitAll()
.requestMatchers("/video/upload").permitAll()
.requestMatchers("/video/list").permitAll()
.requestMatchers("/file/upload").permitAll()
.requestMatchers("/file/list").permitAll()
.requestMatchers("/file/downloadZipFile").permitAll()
.requestMatchers("/comments/upload").permitAll()
.requestMatchers("/comments/**").permitAll()
.requestMatchers("/video/**").permitAll()
.requestMatchers("/login2").permitAll()
.requestMatchers("/listUserbyId/**").permitAll()
.requestMatchers("/updateProfile/**").permitAll()
.requestMatchers("/send-verification-email").permitAll()
.requestMatchers("/hello-world").permitAll()
.requestMatchers("/**").permitAll()
.authorizeHttpRequests(auth -> auth.requestMatchers("/user/register", "/user/error").permitAll()
// .requestMatchers("/listUser").permitAll()
.requestMatchers("/user/login2").permitAll()
.requestMatchers("/user/login3").permitAll()
.requestMatchers("/user/listUserbyId/**").permitAll()
.requestMatchers("/user/hello-world").permitAll()
.requestMatchers("/user/send-verification-email").permitAll()
.requestMatchers("/user/logout").permitAll()
.requestMatchers("/user/listUserbyUsername").permitAll()
.requestMatchers("/user/listUserbyId/**").permitAll()
.requestMatchers("/user/updateProfile/**").permitAll()
.requestMatchers("/user/changePassword/**").permitAll()
.requestMatchers("/user/listUser").permitAll()

.requestMatchers("/user/").authenticated()
.anyRequest().authenticated())
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
.httpBasic(Customizer.withDefaults())
.formLogin(Customizer.withDefaults())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,20 @@
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import com.programming.userService.util.JwtUtil;
import com.programming.userService.entity.CustomUserDetails;
import com.programming.userService.entity.AuthUser;
@RestController
@AllArgsConstructor
@RequestMapping("/user")
public class UserController {

private final AuthUserRepository userRepository;
private final AuthUserRepository userRepository;
private final PasswordEncoder passwordEncoder;

@Autowired
private JwtUtil jwtUtil;

@Autowired
private JavaMailSender javaMailSender;

Expand Down Expand Up @@ -89,13 +95,35 @@ public ResponseEntity registerUser(@RequestBody AuthUser user) {
}

private byte[] getDefaultAvatar() throws IOException {
String defaultAvatarPath = "/app/images/avatar.png"; // Path inside the Docker container
// String defaultAvatarPath = "/app/images/avatar.png"; // Path inside the Docker container
String defaultAvatarPath = "src/main/java/com/programming/userService/images/avatar.png"; // Path on local machine
Path path = Paths.get(defaultAvatarPath);
return Files.readAllBytes(path);
}

@PostMapping("/login3")
public ResponseEntity<?> loginUser3(@RequestBody AuthUser user) {
try {
AuthUser userFromDb = userRepository.findByUsername(user.getUsername())
.orElseThrow(() -> new Exception("User not found"));

if (passwordEncoder.matches(user.getPassword(), userFromDb.getPassword())) {
// Chuyển AuthUser sang CustomUserDetails
CustomUserDetails userDetails = new CustomUserDetails(userFromDb);
String token = jwtUtil.generateToken(userDetails); // Tạo JWT token với UserDetails
Map<String, String> response = new HashMap<>();
response.put("token", token);
return ResponseEntity.ok(response);
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");
}
} catch (Exception e) {
return ResponseEntity.internalServerError().body(e.getMessage());
}
}

@PostMapping("/login2")
public ResponseEntity loginUser(@RequestBody AuthUser user) {
public ResponseEntity loginUser2(@RequestBody AuthUser user) {
try {
AuthUser userFromDb = userRepository.findByUsername(user.getUsername())
.orElseThrow(() -> new Exception("User not found"));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.programming.userService.entity;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Collections;

public class CustomUserDetails implements UserDetails {

private final AuthUser authUser;

public CustomUserDetails(AuthUser authUser) {
this.authUser = authUser;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.emptyList(); // Thêm danh sách quyền nếu cần thiết
}

@Override
public String getPassword() {
return authUser.getPassword();
}

@Override
public String getUsername() {
return authUser.getUsername();
}

@Override
public boolean isAccountNonExpired() {
return true;
}

@Override
public boolean isAccountNonLocked() {
return true;
}

@Override
public boolean isCredentialsNonExpired() {
return true;
}

@Override
public boolean isEnabled() {
return true;
}
}
56 changes: 56 additions & 0 deletions src/main/java/com/programming/userService/util/JwtUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.programming.userService.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;


@Service
public class JwtUtil {
private String SECRET_KEY = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; // Thay đổi SECRET_KEY với giá trị bảo mật của bạn

public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}

public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}

public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}

private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}

private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}

public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}

private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // Token có hiệu lực trong 10
// giờ
.signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
}

public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}

0 comments on commit 337c06e

Please sign in to comment.