Skip to content

Commit

Permalink
feat: add logout logic
Browse files Browse the repository at this point in the history
  • Loading branch information
ShulV committed Oct 23, 2023
1 parent e92d4bd commit a12aea7
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.shulpov.spots_app.auth.requests.AuthenticationRequest;
import com.shulpov.spots_app.auth.requests.RegisterRequest;
import com.shulpov.spots_app.auth.responses.AuthenticationResponse;
import com.shulpov.spots_app.auth.responses.LogoutMessageResponse;
import com.shulpov.spots_app.auth.responses.RegisterErrorResponse;
import com.shulpov.spots_app.auth.responses.RegisterResponse;
import com.shulpov.spots_app.auth.services.AuthenticationService;
Expand All @@ -13,7 +14,6 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
Expand All @@ -32,10 +32,7 @@
@RequiredArgsConstructor
public class AuthenticationController {

@Autowired
private final AuthenticationService service;

@Autowired
private final DtoConverter dtoConverter;

/**
Expand Down Expand Up @@ -75,6 +72,38 @@ public ResponseEntity<AuthenticationResponse> authenticate(@RequestBody Authenti
return ResponseEntity.ok(service.authenticate(request));
}

/**
* Обновление access и refresh токенов
* @param request объект запроса
* @return ResponseEntity<AuthenticationResponse>
*/
@PostMapping(value="/refresh-token")
public ResponseEntity<AuthenticationResponse> refreshToken(HttpServletRequest request) throws AuthenticationException {
return ResponseEntity.status(HttpStatus.OK).body(service.refreshToken(request));
}

/**
* //TODO
* @param refreshToken
* @return
*/
@DeleteMapping(value = "/logout")
public ResponseEntity<LogoutMessageResponse> logout(@RequestHeader(value = "Authorization") String refreshToken)
throws AuthenticationException {
return ResponseEntity.status(HttpStatus.OK).body(service.logout(refreshToken));
}

/**
* //TODO
* @param refreshToken
* @return
*/
@DeleteMapping(value = "/logout-all")
public ResponseEntity<LogoutMessageResponse> logoutAll(@RequestHeader(value = "Authorization") String refreshToken)
throws AuthenticationException {
return ResponseEntity.status(HttpStatus.OK).body(service.logoutAll(refreshToken));
}

/**
* Обработчик ошибки аутентификации (для неверных логина или пароля)
* @param e исключение, содержащее текст ошибки
Expand All @@ -88,20 +117,14 @@ private ResponseEntity<ErrorMessageResponse> handleBadCredentialsException(BadCr
}

/**
* Обновление access и refresh токенов
* @param request объект запроса
* @return ResponseEntity<AuthenticationResponse>
* //TODO
* @param e
* @return
*/
@PostMapping(value="/refresh-token")
public ResponseEntity<AuthenticationResponse> refreshToken(HttpServletRequest request) throws AuthenticationException {
return ResponseEntity.status(HttpStatus.OK).body(service.refreshToken(request));
}

@ExceptionHandler
private ResponseEntity<ErrorMessageResponse> handleAuthenticationException(AuthenticationException e) {
ErrorMessageResponse response = new ErrorMessageResponse();
response.setErrorMessage(e.getMessage());
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.shulpov.spots_app.auth.responses;

import lombok.*;

@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LogoutMessageResponse {
private String message;
private Long userId;
private long closedSessionNumber;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@
import com.shulpov.spots_app.responses.ValidationErrorResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

/**
* @author Shulpov Victor
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.shulpov.spots_app.auth.requests.AuthenticationRequest;
import com.shulpov.spots_app.auth.requests.RegisterRequest;
import com.shulpov.spots_app.auth.responses.AuthenticationResponse;
import com.shulpov.spots_app.auth.responses.LogoutMessageResponse;
import com.shulpov.spots_app.auth.responses.RegisterResponse;
import com.shulpov.spots_app.auth.token.Token;
import com.shulpov.spots_app.auth.token.TokenRepository;
Expand Down Expand Up @@ -79,7 +80,6 @@ public RegisterResponse register(RegisterRequest request, BindingResult errors)
* @param request учетные данные (логин и пароль)
* @return AuthenticationResponse
*/

public AuthenticationResponse authenticate(AuthenticationRequest request) throws BadCredentialsException {
String email = request.getEmail();
//throws BadCredentialsException
Expand Down Expand Up @@ -116,16 +116,19 @@ private void saveUserToken(User user, String jwtToken, TokenType tokenType) {
tokenRepository.save(token);
}

public AuthenticationResponse refreshToken(
HttpServletRequest request
) throws AuthenticationException {
final String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
/**
* //TODO
* @param authToken
* @return
* @throws AuthenticationException
*/
private Token validateRefreshToken(String authToken) throws AuthenticationException {
final String oldRefreshToken;
//заголовка с refresh токеном нет
if (authHeader == null || !authHeader.startsWith("Refresh ")) {
if (authToken == null || !authToken.startsWith("Refresh ")) {
throw new AuthenticationException("Refresh token not found in headers");
}
oldRefreshToken = authHeader.substring(8);
oldRefreshToken = authToken.substring(8);

//проверка: не протух ли токен
if(jwtService.isTokenExpired(oldRefreshToken)) {
Expand All @@ -141,6 +144,18 @@ public AuthenticationResponse refreshToken(
if(refreshToken.getUser() == null) {
throw new AuthenticationException("Token without user");//такого случаться вообще не должно!
}
return refreshToken;
}

/**
* //TODO
* @param request
* @return
* @throws AuthenticationException
*/
public AuthenticationResponse refreshToken(HttpServletRequest request) throws AuthenticationException {
final String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
Token refreshToken = validateRefreshToken(authHeader);
User user = refreshToken.getUser();
String newAccessToken = jwtService.generateAccessToken(user);
String newRefreshToken = jwtService.generateRefreshToken(user);
Expand All @@ -163,5 +178,36 @@ private AuthenticationResponse createAuthResponse(Long userId, String accessToke
.refreshToken(refreshToken)
.build();
}

/**
* //TODO
* @param refreshToken
* @return
*/
public LogoutMessageResponse logout(String refreshToken) throws AuthenticationException {
Token token = validateRefreshToken(refreshToken);
tokenService.deleteToken(token);
return LogoutMessageResponse.builder()
.closedSessionNumber(1L)
.userId(token.getUser().getId())
.message("Successful logout")
.build();
}

/**
* //TODO
* @param refreshToken
* @return
*/
public LogoutMessageResponse logoutAll(String refreshToken) throws AuthenticationException {
Token token = validateRefreshToken(refreshToken);
long count = tokenService.count();
tokenService.deleteAllTokens(token.getUser().getTokens());
return LogoutMessageResponse.builder()
.closedSessionNumber(count)
.userId(token.getUser().getId())
.message("Successful logout")
.build();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,4 @@ public interface TokenRepository extends JpaRepository<Token, Long> {
List<Token> findByUser(User user);

Optional<Token> findByValue(String value);

void deleteByValue(String value);
}
20 changes: 12 additions & 8 deletions src/main/java/com/shulpov/spots_app/auth/token/TokenService.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package com.shulpov.spots_app.auth.token;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Service
@Transactional
public class TokenService {
private final TokenRepository tokenRepository;

Expand All @@ -19,17 +17,23 @@ public void save(Token token) {
tokenRepository.save(token);
}

@Transactional(readOnly = true)
public Optional<Token> getTokenByValue(String token) {
return tokenRepository.findByValue(token);
}

public void deleteTokenByValue(String value) {
tokenRepository.deleteByValue(value);
}

@Transactional(readOnly = true)
public List<Token> getAllTokens() {
return tokenRepository.findAll();
}

public void deleteToken(Token token) {
tokenRepository.delete(token);
}

public long count() {
return tokenRepository.count();
}

public void deleteAllTokens(List<Token> tokens) {
tokenRepository.deleteAll(tokens);
}
}
14 changes: 1 addition & 13 deletions src/main/java/com/shulpov/spots_app/configs/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

import com.shulpov.spots_app.auth.auth_providers.LoginPasswordAuthenticationProvider;
import com.shulpov.spots_app.auth.filters.JwtAuthenticationFilter;
import com.shulpov.spots_app.auth.logout.CustomLogoutHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

Expand All @@ -20,14 +18,11 @@ public class SecurityConfig {

private final JwtAuthenticationFilter jwtAuthenticationFilter;
private final LoginPasswordAuthenticationProvider loginPasswordAuthenticationProvider;
private final CustomLogoutHandler customLogoutHandler;

public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter,
LoginPasswordAuthenticationProvider loginPasswordAuthenticationProvider,
CustomLogoutHandler customLogoutHandler) {
LoginPasswordAuthenticationProvider loginPasswordAuthenticationProvider) {
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
this.loginPasswordAuthenticationProvider = loginPasswordAuthenticationProvider;
this.customLogoutHandler = customLogoutHandler;
}

@Bean
Expand Down Expand Up @@ -67,13 +62,6 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
.authenticationProvider(loginPasswordAuthenticationProvider)
//фильтр для проверки токенов всех запросов
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
//
.logout()
.logoutUrl("/api/v1/auth/logout")
.addLogoutHandler(customLogoutHandler)
.logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext())
//
.and()
.build();
}
}
Expand Down
Loading

0 comments on commit a12aea7

Please sign in to comment.