Skip to content

Commit

Permalink
Merge branch 'phuuthanh2003:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
huyhoang-doit authored Jun 7, 2024
2 parents f4a96ee + 9ab100f commit f93c34f
Show file tree
Hide file tree
Showing 17 changed files with 582 additions and 230 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified .vs/AuctionWebApp_BE/v17/.wsuo
Binary file not shown.
2 changes: 1 addition & 1 deletion .vs/AuctionWebApp_BE/v17/DocumentLayout.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"Version": 1,
"WorkspaceRootPath": "E:\\SWP391-PASSED\\AuctionWebApp_BE\\",
"WorkspaceRootPath": "D:\\Study\\CN5\\SWP\\software-development-project-main\\AuctionWebApp_BE\\",
"Documents": [],
"DocumentGroupContainers": [
{
Expand Down
Binary file modified .vs/slnx.sqlite
Binary file not shown.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
[![Spring Boot CI](https://github.com/phuuthanh2003/AuctionWebApp_BE/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/phuuthanh2003/AuctionWebApp_BE/actions/workflows/ci.yml) [![Release Auction REST API](https://github.com/phuuthanh2003/AuctionWebApp_BE/actions/workflows/release.yml/badge.svg)](https://github.com/phuuthanh2003/AuctionWebApp_BE/actions/workflows/release.yml) [![Publish Auction Backend Docker Image](https://github.com/phuuthanh2003/AuctionWebApp_BE/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/phuuthanh2003/AuctionWebApp_BE/actions/workflows/docker-publish.yml)

3 changes: 2 additions & 1 deletion db/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ VALUES (N'DOJI', N'Nhẫn đính hôn bằng kim cương.', N'Bạc', N'NHẪN
1),
(N'DOJI', N'Nhẫn đính hôn bằng kim cương.', N'Bạc', N'NHẪN KIM CƯƠNG FDR0257', 41130000, 'ACTIVE', 20.1, 2, 1),
(N'DOJI', N'Nhẫn đính hôn bằng kim cương.', N'Bạc', N'NHẪN KIM CƯƠNG DJR397-22', 37000000, 'ACTIVE', 10.0, 2,
1);
1),
(N'Fine Jewelry', N'Dây chuyền kim cương', N'Vàng', N'Dây chuyền kim cương Y', 18000000, 'ACTIVE', 6.9, 1, 15);

CREATE TABLE [dbo].[auction]
(
Expand Down
2 changes: 1 addition & 1 deletion get_version.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Define the fixed version
version="0.0.2"
version="0.0.3"

# Output the fixed version
echo "$version"
11 changes: 11 additions & 0 deletions render.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# render.yaml
services:
- type: web
name: AuctionWebApp_BE
runtime: docker
repo: https://github.com/phuuthanh2003/AuctionWebApp_BE
plan: free
region: oregon
dockerContext: .
dockerfilePath: ./docker-compose.yml
version: "1"
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import vn.webapp.backend.auction.dto.*;
import vn.webapp.backend.auction.dto.RegisterAccountRequest;
import vn.webapp.backend.auction.service.AuthenticationService;
import vn.webapp.backend.auction.service.JwtService;
import vn.webapp.backend.auction.service.AuthenticationServiceImpl;

import java.io.IOException;

Expand All @@ -21,7 +18,7 @@
@CrossOrigin(origins = {"http://localhost:3000", "http://localhost:3001"})
public class AuthenticationController {

private final AuthenticationService authenticationService;
private final AuthenticationServiceImpl authenticationService;

@PostMapping("/authenticate")
public ResponseEntity<AuthenticationResponse> authenticate(
Expand Down Expand Up @@ -65,4 +62,12 @@ public ResponseEntity<AuthenticationResponse> forgotPassword(
authenticationService.forgotPassword(request);
return ResponseEntity.ok().build();
}

@PostMapping("/reset-password")
public ResponseEntity<AuthenticationResponse> resetPassword(
@RequestBody ResetPasswordRequest request) {
return ResponseEntity.ok(authenticationService.resetPassword(request));
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package vn.webapp.backend.auction.dto;

public record ResetPasswordRequest(
String token,
String password) {
}
Original file line number Diff line number Diff line change
@@ -1,243 +1,31 @@
package vn.webapp.backend.auction.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.mail.MessagingException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import vn.webapp.backend.auction.dto.*;
import vn.webapp.backend.auction.dto.RegisterAccountRequest;
import vn.webapp.backend.auction.enums.AccountState;
import vn.webapp.backend.auction.enums.Role;
import vn.webapp.backend.auction.enums.TokenType;
import vn.webapp.backend.auction.exception.*;
import vn.webapp.backend.auction.model.Bank;
import vn.webapp.backend.auction.model.Token;
import vn.webapp.backend.auction.model.User;
import vn.webapp.backend.auction.repository.BankRepository;
import vn.webapp.backend.auction.repository.TokenRepository;
import vn.webapp.backend.auction.repository.UserRepository;
import vn.webapp.backend.auction.service.email.EmailService;

import java.io.IOException;
import java.time.LocalDateTime;


@Service
@RequiredArgsConstructor
public class AuthenticationService {
private final UserRepository userRepository;
private final EmailService emailService;
private final BankRepository bankRepository;
private final JwtService jwtService;
private final AuthenticationManager authenticationManager;
private final PasswordEncoder passwordEncoder;
private final TokenRepository tokenRepository;

public AuthenticationResponse authenticate(AuthenticationRequest request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws MessagingException {
var user = userRepository.findByUsername(request.username())
.orElseGet(() -> userRepository.findByEmail(request.username())
.orElseThrow(() -> new ResourceNotFoundException(
"Người dùng với username hoặc email: " + request.username()
+ " không tồn tại. Vui lòng đăng ký tài khoản mới.")));
if (user.getState() == AccountState.INACTIVE) {
emailService.sendActivationEmail(user.getEmail(), user.getFullName(),
jwtService.generateToken(user));
throw new AccountInactiveException("Tài khoản chưa kích hoạt, vui lòng kiểm tra email để kích hoạt tài khoản.");
} else if (user.getState() == AccountState.DISABLE) {
throw new AccountDisabledException("Tài khoản với username: " + request.username() + " đã bị vô hiệu hóa.");
} else if (user.getState() == AccountState.ACTIVE) {

authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
request.username(),
request.password()));

String ipAddress = httpServletRequest.getRemoteAddr();
String deviceInfo = httpServletRequest.getHeader("User-Agent");

var jwtToken = jwtService.generateToken(user);
var refreshToken = jwtService.generateRefreshToken(user);

ResponseCookie refreshTokenCookie = jwtService.generateRefreshTokenCookie(refreshToken);
httpServletResponse.addHeader("Set-Cookie", refreshTokenCookie.toString());

revokeAllUserTokens(user);
saveUserToken(user, jwtToken, refreshToken, ipAddress, deviceInfo);
return AuthenticationResponse.builder()
.accessToken(jwtToken)
.build();
}
return null;
}
public interface AuthenticationService {
public AuthenticationResponse authenticate
(AuthenticationRequest request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws MessagingException;

private void saveUserToken(User user, String jwtToken, String refreshToken, String ipAddress, String deviceInfo) {
var token = Token.builder()
.user(user)
.token(jwtToken)
.refreshToken(refreshToken)
.tokenType(TokenType.BEARER)
.expired(false)
.revoked(false)
.createdTime(LocalDateTime.now())
.ipAddress(ipAddress)
.deviceInfo(deviceInfo)
.build();
tokenRepository.save(token);
}

public void activateAccount(ActivateAccountRequest request) throws MessagingException {
var username = jwtService.extractUsername(request.token());
var user = userRepository.findByUsername(username)
.orElseThrow();
if (jwtService.isTokenExpired(request.token())) {
var jwtToken = jwtService.generateToken(user);
emailService.sendActivationEmail(username, user.getFullName(), jwtToken);
throw new ExpiredTokenException(
"Mã kích hoạt đã hết hạn. Vui lòng kiểm tra email để nhận hướng dẫn kích hoạt mới.");
} else {
user.setState(AccountState.ACTIVE);
userRepository.save(user);
}
}
public void activateAccount(ActivateAccountRequest request) throws MessagingException;

public AuthenticationResponse register(RegisterAccountRequest request, HttpServletRequest httpServletRequest) throws MessagingException {
userRepository.findByUsername(request.username())
.ifPresent(user -> {
throw new UserAlreadyExistsException("Người dùng với username: " + request.username() + " đã tồn tại.");
});
userRepository.findByEmail(request.email())
.ifPresent(user -> {
throw new UserAlreadyExistsException("Người dùng với email: " + request.email() + " đã tồn tại.");
});
Bank bank = bankRepository.findById(request.bankId()).get();
var user = User.builder()
.firstName(request.firstName())
.lastName(request.lastName())
.email(request.email())
.username(request.username())
.password(passwordEncoder.encode(request.password()))
.address(request.address())
.district(request.district())
.ward(request.ward())
.city(request.city())
.phone(request.phone())
.avatar("https://www.iconpacks.net/icons/2/free-user-icon-3296-thumb.png")
.yob(request.yob())
.role(request.role())
.CCCD(request.CCCD())
.state(AccountState.INACTIVE)
.bankAccountName(request.bankAccountName())
.bankAccountNumber(request.bankAccountNumber())
.bank(bank)
.build();
var savedUser = userRepository.save(user);
var jwtToken = jwtService.generateToken(user);
var refreshToken = jwtService.generateRefreshToken(user);

String ipAddress = httpServletRequest.getRemoteAddr();
String deviceInfo = httpServletRequest.getHeader("User-Agent");

saveUserToken(savedUser, jwtToken, refreshToken, ipAddress, deviceInfo);
emailService.sendActivationEmail(request.email(), user.getFullName(), jwtToken);
return AuthenticationResponse.builder()
.accessToken(jwtToken)
.build();
}

private void revokeAllUserTokens(User user) {
var validUserTokens = tokenRepository.findAllValidTokenByUser(user.getId());
if (validUserTokens.isEmpty())
return;
validUserTokens.forEach(token -> {
token.setExpired(true);
token.setRevoked(true);
});
tokenRepository.saveAll(validUserTokens);
}
public AuthenticationResponse register(RegisterAccountRequest request, HttpServletRequest httpServletRequest) throws MessagingException;

public void refreshToken(
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
final String username;

final String oldRefreshToken = jwtService.getTokenFromCookie(request, "refresh_token");
if (oldRefreshToken != null) {
username = jwtService.extractUsername(oldRefreshToken);
if (username != null) {
var user = userRepository.findByUsername(username)
.orElseThrow();
if (jwtService.isTokenValid(oldRefreshToken, user)) {
var tokenOptional = tokenRepository.findByRefreshToken(oldRefreshToken);

if (tokenOptional.isPresent() && !tokenOptional.get().expired && !tokenOptional.get().revoked) {
var accessToken = jwtService.generateToken(user);
var newRefreshToken = jwtService.generateRefreshToken(user);
revokeAllUserTokens(user);

String ipAddress = request.getRemoteAddr();
String deviceInfo = request.getHeader("User-Agent");

saveUserToken(user, accessToken, newRefreshToken, ipAddress, deviceInfo);
) throws IOException;

ResponseCookie refreshTokenCookie = jwtService.generateRefreshTokenCookie(newRefreshToken);
response.addHeader("Set-Cookie", refreshTokenCookie.toString());
public AuthenticationResponse changePassword(ChangePasswordRequest request);

var authResponse = AuthenticationResponse.builder()
.accessToken(accessToken)
.build();
new ObjectMapper().writeValue(response.getOutputStream(), authResponse);
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token is expired or revoked");
}
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid refresh token");
}
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Refresh token not found");
}
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Refresh token not found");
}
}
public void forgotPassword(ForgotPasswordRequest request) throws MessagingException;

public AuthenticationResponse changePassword(ChangePasswordRequest request) {
var user = userRepository.findByUsername(jwtService.extractUsername(request.token()))
.orElseThrow();
// var user = userRepository.findByUsername(request.username())
// .orElseThrow();
if (!passwordEncoder.matches(request.oldPassword(), user.getPassword())) {
throw new OldPasswordMismatchException("Mật khẩu cũ không đúng.");
}
user.setPassword(passwordEncoder.encode(request.newPassword()));
userRepository.save(user);
var jwtToken = jwtService.generateToken(user);
return AuthenticationResponse.builder()
.accessToken(jwtToken)
.build();
}
public AuthenticationResponse resetPassword(ResetPasswordRequest request);

public void forgotPassword(ForgotPasswordRequest request) throws MessagingException {
var existingUser = userRepository.findByEmail(request.email())
.orElseThrow(() -> new UserNotFoundException(
"Người dùng với email '" + request.email() + "' không tồn tại."));
if (existingUser.getRole() != Role.MEMBER) {
throw new UnauthorizedException(
"Bạn không có quyền truy cập. Vui lòng liên hệ quản trị viên để được hỗ trợ.");
}
emailService.sendResetPasswordEmail(request.email(), existingUser.getFullName(),
jwtService.generateToken(existingUser));
}
}
Loading

0 comments on commit f93c34f

Please sign in to comment.