Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ To build and run the project, follow these steps:
* Run the project: mvn spring-boot:run

-> The application will be available at http://localhost:8080.
END.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.4</version>
<version>3.3.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.alibou</groupId>
Expand Down
52 changes: 24 additions & 28 deletions src/main/java/com/alibou/security/SecurityApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.alibou.security.auth.AuthenticationService;
import com.alibou.security.auth.RegisterRequest;
import com.alibou.security.user.Role;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
Expand All @@ -16,33 +15,30 @@
@EnableJpaAuditing(auditorAwareRef = "auditorAware")
public class SecurityApplication {

public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class, args);
}
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class, args);
}

@Bean
public CommandLineRunner commandLineRunner(
AuthenticationService service
) {
return args -> {
var admin = RegisterRequest.builder()
.firstname("Admin")
.lastname("Admin")
.email("[email protected]")
.password("password")
.role(ADMIN)
.build();
System.out.println("Admin token: " + service.register(admin).getAccessToken());
@Bean
public CommandLineRunner commandLineRunner(AuthenticationService service) {
return args -> {
var admin = RegisterRequest.builder()
.firstname("Admin")
.lastname("Admin")
.email("[email protected]")
.password("password")
.role(ADMIN)
.build();
System.out.println("Admin token: " + service.register(admin).getAccessToken());

var manager = RegisterRequest.builder()
.firstname("Admin")
.lastname("Admin")
.email("[email protected]")
.password("password")
.role(MANAGER)
.build();
System.out.println("Manager token: " + service.register(manager).getAccessToken());

};
}
var manager = RegisterRequest.builder()
.firstname("Manager")
.lastname("Manager")
.email("[email protected]")
.password("password")
.role(MANAGER)
.build();
System.out.println("Manager token: " + service.register(manager).getAccessToken());
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
import java.util.Optional;

public class ApplicationAuditAware implements AuditorAware<Integer> {

@Override
public Optional<Integer> getCurrentAuditor() {
Authentication authentication =
SecurityContextHolder
.getContext()
.getAuthentication();
if (authentication == null ||
!authentication.isAuthenticated() ||
!authentication.isAuthenticated() ||
authentication instanceof AnonymousAuthenticationToken
) {
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,20 @@
@RequiredArgsConstructor
public class AuthenticationController {

private final AuthenticationService service;

@PostMapping("/register")
public ResponseEntity<AuthenticationResponse> register(
@RequestBody RegisterRequest request
) {
return ResponseEntity.ok(service.register(request));
}
@PostMapping("/authenticate")
public ResponseEntity<AuthenticationResponse> authenticate(
@RequestBody AuthenticationRequest request
) {
return ResponseEntity.ok(service.authenticate(request));
}

@PostMapping("/refresh-token")
public void refreshToken(
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
service.refreshToken(request, response);
}


private final AuthenticationService service;

@PostMapping("/register")
public ResponseEntity<AuthenticationResponse> register(@RequestBody RegisterRequest request) {
return ResponseEntity.ok(service.register(request));
}

@PostMapping("/authenticate")
public ResponseEntity<AuthenticationResponse> authenticate(@RequestBody AuthenticationRequest request) {
return ResponseEntity.ok(service.authenticate(request));
}

@PostMapping("/refresh-token")
public void refreshToken(HttpServletRequest request, HttpServletResponse response) throws IOException {
service.refreshToken(request, response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
@NoArgsConstructor
public class AuthenticationRequest {

private String email;
String password;
private String email;
String password;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
@NoArgsConstructor
public class AuthenticationResponse {

@JsonProperty("access_token")
private String accessToken;
@JsonProperty("refresh_token")
private String refreshToken;
@JsonProperty("access_token")
private String accessToken;
@JsonProperty("refresh_token")
private String refreshToken;
}
168 changes: 83 additions & 85 deletions src/main/java/com/alibou/security/auth/AuthenticationService.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,96 +25,94 @@
@Service
@RequiredArgsConstructor
public class AuthenticationService {
private final UserRepository repository;
private final TokenRepository tokenRepository;
private final PasswordEncoder passwordEncoder;
private final JwtService jwtService;
private final AuthenticationManager authenticationManager;

public AuthenticationResponse register(RegisterRequest request) {
var user = User.builder()
.firstname(request.getFirstname())
.lastname(request.getLastname())
.email(request.getEmail())
.password(passwordEncoder.encode(request.getPassword()))
.role(request.getRole())
.build();
var savedUser = repository.save(user);
var jwtToken = jwtService.generateToken(user);
var refreshToken = jwtService.generateRefreshToken(user);
saveUserToken(savedUser, jwtToken);
return AuthenticationResponse.builder()
.accessToken(jwtToken)
.refreshToken(refreshToken)
.build();
}
private final UserRepository repository;
private final TokenRepository tokenRepository;
private final PasswordEncoder passwordEncoder;
private final JwtService jwtService;
private final AuthenticationManager authenticationManager;

public AuthenticationResponse authenticate(AuthenticationRequest request) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
request.getEmail(),
request.getPassword()
)
);
var user = repository.findByEmail(request.getEmail())
.orElseThrow();
var jwtToken = jwtService.generateToken(user);
var refreshToken = jwtService.generateRefreshToken(user);
revokeAllUserTokens(user);
saveUserToken(user, jwtToken);
return AuthenticationResponse.builder()
.accessToken(jwtToken)
.refreshToken(refreshToken)
.build();
}

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

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 void refreshToken(
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
final String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
final String refreshToken;
final String userEmail;
if (authHeader == null ||!authHeader.startsWith("Bearer ")) {
return;
public AuthenticationResponse register(RegisterRequest request) {
var user = User.builder()
.firstname(request.getFirstname())
.lastname(request.getLastname())
.email(request.getEmail())
.password(passwordEncoder.encode(request.getPassword()))
.role(request.getRole())
.build();
var savedUser = repository.save(user);
var jwtToken = jwtService.generateToken(user);
var refreshToken = jwtService.generateRefreshToken(user);
saveUserToken(savedUser, jwtToken);
return AuthenticationResponse.builder()
.accessToken(jwtToken)
.refreshToken(refreshToken)
.build();
}
refreshToken = authHeader.substring(7);
userEmail = jwtService.extractUsername(refreshToken);
if (userEmail != null) {
var user = this.repository.findByEmail(userEmail)
.orElseThrow();
if (jwtService.isTokenValid(refreshToken, user)) {
var accessToken = jwtService.generateToken(user);

public AuthenticationResponse authenticate(AuthenticationRequest request) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
request.getEmail(),
request.getPassword()
)
);
var user = repository.findByEmail(request.getEmail())
.orElseThrow();
var jwtToken = jwtService.generateToken(user);
var refreshToken = jwtService.generateRefreshToken(user);
revokeAllUserTokens(user);
saveUserToken(user, accessToken);
var authResponse = AuthenticationResponse.builder()
.accessToken(accessToken)
saveUserToken(user, jwtToken);
return AuthenticationResponse.builder()
.accessToken(jwtToken)
.refreshToken(refreshToken)
.build();
new ObjectMapper().writeValue(response.getOutputStream(), authResponse);
}
}
}

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

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 void refreshToken(HttpServletRequest request, HttpServletResponse response) throws IOException {
final String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
final String refreshToken;
final String userEmail;
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
return;
}
refreshToken = authHeader.substring(7);
userEmail = jwtService.extractUsername(refreshToken);
if (userEmail != null) {
var user = this.repository.findByEmail(userEmail)
.orElseThrow();
if (jwtService.isTokenValid(refreshToken, user)) {
var accessToken = jwtService.generateToken(user);
revokeAllUserTokens(user);
saveUserToken(user, accessToken);
var authResponse = AuthenticationResponse.builder()
.accessToken(accessToken)
.refreshToken(refreshToken)
.build();
new ObjectMapper().writeValue(response.getOutputStream(), authResponse);
}
}
}
}
10 changes: 5 additions & 5 deletions src/main/java/com/alibou/security/auth/RegisterRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
@NoArgsConstructor
public class RegisterRequest {

private String firstname;
private String lastname;
private String email;
private String password;
private Role role;
private String firstname;
private String lastname;
private String email;
private String password;
private Role role;
}
11 changes: 2 additions & 9 deletions src/main/java/com/alibou/security/book/Book.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,15 @@ public class Book {
private String isbn;

@CreatedDate
@Column(
nullable = false,
updatable = false
)
@Column(nullable = false, updatable = false)
private LocalDateTime createDate;

@LastModifiedDate
@Column(insertable = false)
private LocalDateTime lastModified;


@CreatedBy
@Column(
nullable = false,
updatable = false
)
@Column(nullable = false, updatable = false)
private Integer createdBy;

@LastModifiedBy
Expand Down
4 changes: 1 addition & 3 deletions src/main/java/com/alibou/security/book/BookController.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ public class BookController {
private final BookService service;

@PostMapping
public ResponseEntity<?> save(
@RequestBody BookRequest request
) {
public ResponseEntity<?> save(@RequestBody BookRequest request) {
service.save(request);
return ResponseEntity.accepted().build();
}
Expand Down
Loading